socket.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.Socket = void 0;
  7. const socket_io_parser_1 = require("socket.io-parser");
  8. const on_js_1 = require("./on.js");
  9. const component_emitter_1 = require("@socket.io/component-emitter");
  10. const debug_1 = __importDefault(require("debug")); // debug()
  11. const debug = debug_1.default("socket.io-client:socket"); // debug()
  12. /**
  13. * Internal events.
  14. * These events can't be emitted by the user.
  15. */
  16. const RESERVED_EVENTS = Object.freeze({
  17. connect: 1,
  18. connect_error: 1,
  19. disconnect: 1,
  20. disconnecting: 1,
  21. // EventEmitter reserved events: https://nodejs.org/api/events.html#events_event_newlistener
  22. newListener: 1,
  23. removeListener: 1,
  24. });
  25. /**
  26. * A Socket is the fundamental class for interacting with the server.
  27. *
  28. * A Socket belongs to a certain Namespace (by default /) and uses an underlying {@link Manager} to communicate.
  29. *
  30. * @example
  31. * const socket = io();
  32. *
  33. * socket.on("connect", () => {
  34. * console.log("connected");
  35. * });
  36. *
  37. * // send an event to the server
  38. * socket.emit("foo", "bar");
  39. *
  40. * socket.on("foobar", () => {
  41. * // an event was received from the server
  42. * });
  43. *
  44. * // upon disconnection
  45. * socket.on("disconnect", (reason) => {
  46. * console.log(`disconnected due to ${reason}`);
  47. * });
  48. */
  49. class Socket extends component_emitter_1.Emitter {
  50. /**
  51. * `Socket` constructor.
  52. */
  53. constructor(io, nsp, opts) {
  54. super();
  55. /**
  56. * Whether the socket is currently connected to the server.
  57. *
  58. * @example
  59. * const socket = io();
  60. *
  61. * socket.on("connect", () => {
  62. * console.log(socket.connected); // true
  63. * });
  64. *
  65. * socket.on("disconnect", () => {
  66. * console.log(socket.connected); // false
  67. * });
  68. */
  69. this.connected = false;
  70. /**
  71. * Whether the connection state was recovered after a temporary disconnection. In that case, any missed packets will
  72. * be transmitted by the server.
  73. */
  74. this.recovered = false;
  75. /**
  76. * Buffer for packets received before the CONNECT packet
  77. */
  78. this.receiveBuffer = [];
  79. /**
  80. * Buffer for packets that will be sent once the socket is connected
  81. */
  82. this.sendBuffer = [];
  83. /**
  84. * The queue of packets to be sent with retry in case of failure.
  85. *
  86. * Packets are sent one by one, each waiting for the server acknowledgement, in order to guarantee the delivery order.
  87. * @private
  88. */
  89. this._queue = [];
  90. /**
  91. * A sequence to generate the ID of the {@link QueuedPacket}.
  92. * @private
  93. */
  94. this._queueSeq = 0;
  95. this.ids = 0;
  96. this.acks = {};
  97. this.flags = {};
  98. this.io = io;
  99. this.nsp = nsp;
  100. if (opts && opts.auth) {
  101. this.auth = opts.auth;
  102. }
  103. this._opts = Object.assign({}, opts);
  104. if (this.io._autoConnect)
  105. this.open();
  106. }
  107. /**
  108. * Whether the socket is currently disconnected
  109. *
  110. * @example
  111. * const socket = io();
  112. *
  113. * socket.on("connect", () => {
  114. * console.log(socket.disconnected); // false
  115. * });
  116. *
  117. * socket.on("disconnect", () => {
  118. * console.log(socket.disconnected); // true
  119. * });
  120. */
  121. get disconnected() {
  122. return !this.connected;
  123. }
  124. /**
  125. * Subscribe to open, close and packet events
  126. *
  127. * @private
  128. */
  129. subEvents() {
  130. if (this.subs)
  131. return;
  132. const io = this.io;
  133. this.subs = [
  134. on_js_1.on(io, "open", this.onopen.bind(this)),
  135. on_js_1.on(io, "packet", this.onpacket.bind(this)),
  136. on_js_1.on(io, "error", this.onerror.bind(this)),
  137. on_js_1.on(io, "close", this.onclose.bind(this)),
  138. ];
  139. }
  140. /**
  141. * Whether the Socket will try to reconnect when its Manager connects or reconnects.
  142. *
  143. * @example
  144. * const socket = io();
  145. *
  146. * console.log(socket.active); // true
  147. *
  148. * socket.on("disconnect", (reason) => {
  149. * if (reason === "io server disconnect") {
  150. * // the disconnection was initiated by the server, you need to manually reconnect
  151. * console.log(socket.active); // false
  152. * }
  153. * // else the socket will automatically try to reconnect
  154. * console.log(socket.active); // true
  155. * });
  156. */
  157. get active() {
  158. return !!this.subs;
  159. }
  160. /**
  161. * "Opens" the socket.
  162. *
  163. * @example
  164. * const socket = io({
  165. * autoConnect: false
  166. * });
  167. *
  168. * socket.connect();
  169. */
  170. connect() {
  171. if (this.connected)
  172. return this;
  173. this.subEvents();
  174. if (!this.io["_reconnecting"])
  175. this.io.open(); // ensure open
  176. if ("open" === this.io._readyState)
  177. this.onopen();
  178. return this;
  179. }
  180. /**
  181. * Alias for {@link connect()}.
  182. */
  183. open() {
  184. return this.connect();
  185. }
  186. /**
  187. * Sends a `message` event.
  188. *
  189. * This method mimics the WebSocket.send() method.
  190. *
  191. * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
  192. *
  193. * @example
  194. * socket.send("hello");
  195. *
  196. * // this is equivalent to
  197. * socket.emit("message", "hello");
  198. *
  199. * @return self
  200. */
  201. send(...args) {
  202. args.unshift("message");
  203. this.emit.apply(this, args);
  204. return this;
  205. }
  206. /**
  207. * Override `emit`.
  208. * If the event is in `events`, it's emitted normally.
  209. *
  210. * @example
  211. * socket.emit("hello", "world");
  212. *
  213. * // all serializable datastructures are supported (no need to call JSON.stringify)
  214. * socket.emit("hello", 1, "2", { 3: ["4"], 5: Uint8Array.from([6]) });
  215. *
  216. * // with an acknowledgement from the server
  217. * socket.emit("hello", "world", (val) => {
  218. * // ...
  219. * });
  220. *
  221. * @return self
  222. */
  223. emit(ev, ...args) {
  224. if (RESERVED_EVENTS.hasOwnProperty(ev)) {
  225. throw new Error('"' + ev.toString() + '" is a reserved event name');
  226. }
  227. args.unshift(ev);
  228. if (this._opts.retries && !this.flags.fromQueue && !this.flags.volatile) {
  229. this._addToQueue(args);
  230. return this;
  231. }
  232. const packet = {
  233. type: socket_io_parser_1.PacketType.EVENT,
  234. data: args,
  235. };
  236. packet.options = {};
  237. packet.options.compress = this.flags.compress !== false;
  238. // event ack callback
  239. if ("function" === typeof args[args.length - 1]) {
  240. const id = this.ids++;
  241. debug("emitting packet with ack id %d", id);
  242. const ack = args.pop();
  243. this._registerAckCallback(id, ack);
  244. packet.id = id;
  245. }
  246. const isTransportWritable = this.io.engine &&
  247. this.io.engine.transport &&
  248. this.io.engine.transport.writable;
  249. const discardPacket = this.flags.volatile && (!isTransportWritable || !this.connected);
  250. if (discardPacket) {
  251. debug("discard packet as the transport is not currently writable");
  252. }
  253. else if (this.connected) {
  254. this.notifyOutgoingListeners(packet);
  255. this.packet(packet);
  256. }
  257. else {
  258. this.sendBuffer.push(packet);
  259. }
  260. this.flags = {};
  261. return this;
  262. }
  263. /**
  264. * @private
  265. */
  266. _registerAckCallback(id, ack) {
  267. var _a;
  268. const timeout = (_a = this.flags.timeout) !== null && _a !== void 0 ? _a : this._opts.ackTimeout;
  269. if (timeout === undefined) {
  270. this.acks[id] = ack;
  271. return;
  272. }
  273. // @ts-ignore
  274. const timer = this.io.setTimeoutFn(() => {
  275. delete this.acks[id];
  276. for (let i = 0; i < this.sendBuffer.length; i++) {
  277. if (this.sendBuffer[i].id === id) {
  278. debug("removing packet with ack id %d from the buffer", id);
  279. this.sendBuffer.splice(i, 1);
  280. }
  281. }
  282. debug("event with ack id %d has timed out after %d ms", id, timeout);
  283. ack.call(this, new Error("operation has timed out"));
  284. }, timeout);
  285. this.acks[id] = (...args) => {
  286. // @ts-ignore
  287. this.io.clearTimeoutFn(timer);
  288. ack.apply(this, [null, ...args]);
  289. };
  290. }
  291. /**
  292. * Emits an event and waits for an acknowledgement
  293. *
  294. * @example
  295. * // without timeout
  296. * const response = await socket.emitWithAck("hello", "world");
  297. *
  298. * // with a specific timeout
  299. * try {
  300. * const response = await socket.timeout(1000).emitWithAck("hello", "world");
  301. * } catch (err) {
  302. * // the server did not acknowledge the event in the given delay
  303. * }
  304. *
  305. * @return a Promise that will be fulfilled when the server acknowledges the event
  306. */
  307. emitWithAck(ev, ...args) {
  308. // the timeout flag is optional
  309. const withErr = this.flags.timeout !== undefined || this._opts.ackTimeout !== undefined;
  310. return new Promise((resolve, reject) => {
  311. args.push((arg1, arg2) => {
  312. if (withErr) {
  313. return arg1 ? reject(arg1) : resolve(arg2);
  314. }
  315. else {
  316. return resolve(arg1);
  317. }
  318. });
  319. this.emit(ev, ...args);
  320. });
  321. }
  322. /**
  323. * Add the packet to the queue.
  324. * @param args
  325. * @private
  326. */
  327. _addToQueue(args) {
  328. let ack;
  329. if (typeof args[args.length - 1] === "function") {
  330. ack = args.pop();
  331. }
  332. const packet = {
  333. id: this._queueSeq++,
  334. tryCount: 0,
  335. pending: false,
  336. args,
  337. flags: Object.assign({ fromQueue: true }, this.flags),
  338. };
  339. args.push((err, ...responseArgs) => {
  340. if (packet !== this._queue[0]) {
  341. // the packet has already been acknowledged
  342. return;
  343. }
  344. const hasError = err !== null;
  345. if (hasError) {
  346. if (packet.tryCount > this._opts.retries) {
  347. debug("packet [%d] is discarded after %d tries", packet.id, packet.tryCount);
  348. this._queue.shift();
  349. if (ack) {
  350. ack(err);
  351. }
  352. }
  353. }
  354. else {
  355. debug("packet [%d] was successfully sent", packet.id);
  356. this._queue.shift();
  357. if (ack) {
  358. ack(null, ...responseArgs);
  359. }
  360. }
  361. packet.pending = false;
  362. return this._drainQueue();
  363. });
  364. this._queue.push(packet);
  365. this._drainQueue();
  366. }
  367. /**
  368. * Send the first packet of the queue, and wait for an acknowledgement from the server.
  369. * @param force - whether to resend a packet that has not been acknowledged yet
  370. *
  371. * @private
  372. */
  373. _drainQueue(force = false) {
  374. debug("draining queue");
  375. if (!this.connected || this._queue.length === 0) {
  376. return;
  377. }
  378. const packet = this._queue[0];
  379. if (packet.pending && !force) {
  380. debug("packet [%d] has already been sent and is waiting for an ack", packet.id);
  381. return;
  382. }
  383. packet.pending = true;
  384. packet.tryCount++;
  385. debug("sending packet [%d] (try n°%d)", packet.id, packet.tryCount);
  386. this.flags = packet.flags;
  387. this.emit.apply(this, packet.args);
  388. }
  389. /**
  390. * Sends a packet.
  391. *
  392. * @param packet
  393. * @private
  394. */
  395. packet(packet) {
  396. packet.nsp = this.nsp;
  397. this.io._packet(packet);
  398. }
  399. /**
  400. * Called upon engine `open`.
  401. *
  402. * @private
  403. */
  404. onopen() {
  405. debug("transport is open - connecting");
  406. if (typeof this.auth == "function") {
  407. this.auth((data) => {
  408. this._sendConnectPacket(data);
  409. });
  410. }
  411. else {
  412. this._sendConnectPacket(this.auth);
  413. }
  414. }
  415. /**
  416. * Sends a CONNECT packet to initiate the Socket.IO session.
  417. *
  418. * @param data
  419. * @private
  420. */
  421. _sendConnectPacket(data) {
  422. this.packet({
  423. type: socket_io_parser_1.PacketType.CONNECT,
  424. data: this._pid
  425. ? Object.assign({ pid: this._pid, offset: this._lastOffset }, data)
  426. : data,
  427. });
  428. }
  429. /**
  430. * Called upon engine or manager `error`.
  431. *
  432. * @param err
  433. * @private
  434. */
  435. onerror(err) {
  436. if (!this.connected) {
  437. this.emitReserved("connect_error", err);
  438. }
  439. }
  440. /**
  441. * Called upon engine `close`.
  442. *
  443. * @param reason
  444. * @param description
  445. * @private
  446. */
  447. onclose(reason, description) {
  448. debug("close (%s)", reason);
  449. this.connected = false;
  450. delete this.id;
  451. this.emitReserved("disconnect", reason, description);
  452. }
  453. /**
  454. * Called with socket packet.
  455. *
  456. * @param packet
  457. * @private
  458. */
  459. onpacket(packet) {
  460. const sameNamespace = packet.nsp === this.nsp;
  461. if (!sameNamespace)
  462. return;
  463. switch (packet.type) {
  464. case socket_io_parser_1.PacketType.CONNECT:
  465. if (packet.data && packet.data.sid) {
  466. this.onconnect(packet.data.sid, packet.data.pid);
  467. }
  468. else {
  469. this.emitReserved("connect_error", new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));
  470. }
  471. break;
  472. case socket_io_parser_1.PacketType.EVENT:
  473. case socket_io_parser_1.PacketType.BINARY_EVENT:
  474. this.onevent(packet);
  475. break;
  476. case socket_io_parser_1.PacketType.ACK:
  477. case socket_io_parser_1.PacketType.BINARY_ACK:
  478. this.onack(packet);
  479. break;
  480. case socket_io_parser_1.PacketType.DISCONNECT:
  481. this.ondisconnect();
  482. break;
  483. case socket_io_parser_1.PacketType.CONNECT_ERROR:
  484. this.destroy();
  485. const err = new Error(packet.data.message);
  486. // @ts-ignore
  487. err.data = packet.data.data;
  488. this.emitReserved("connect_error", err);
  489. break;
  490. }
  491. }
  492. /**
  493. * Called upon a server event.
  494. *
  495. * @param packet
  496. * @private
  497. */
  498. onevent(packet) {
  499. const args = packet.data || [];
  500. debug("emitting event %j", args);
  501. if (null != packet.id) {
  502. debug("attaching ack callback to event");
  503. args.push(this.ack(packet.id));
  504. }
  505. if (this.connected) {
  506. this.emitEvent(args);
  507. }
  508. else {
  509. this.receiveBuffer.push(Object.freeze(args));
  510. }
  511. }
  512. emitEvent(args) {
  513. if (this._anyListeners && this._anyListeners.length) {
  514. const listeners = this._anyListeners.slice();
  515. for (const listener of listeners) {
  516. listener.apply(this, args);
  517. }
  518. }
  519. super.emit.apply(this, args);
  520. if (this._pid && args.length && typeof args[args.length - 1] === "string") {
  521. this._lastOffset = args[args.length - 1];
  522. }
  523. }
  524. /**
  525. * Produces an ack callback to emit with an event.
  526. *
  527. * @private
  528. */
  529. ack(id) {
  530. const self = this;
  531. let sent = false;
  532. return function (...args) {
  533. // prevent double callbacks
  534. if (sent)
  535. return;
  536. sent = true;
  537. debug("sending ack %j", args);
  538. self.packet({
  539. type: socket_io_parser_1.PacketType.ACK,
  540. id: id,
  541. data: args,
  542. });
  543. };
  544. }
  545. /**
  546. * Called upon a server acknowlegement.
  547. *
  548. * @param packet
  549. * @private
  550. */
  551. onack(packet) {
  552. const ack = this.acks[packet.id];
  553. if ("function" === typeof ack) {
  554. debug("calling ack %s with %j", packet.id, packet.data);
  555. ack.apply(this, packet.data);
  556. delete this.acks[packet.id];
  557. }
  558. else {
  559. debug("bad ack %s", packet.id);
  560. }
  561. }
  562. /**
  563. * Called upon server connect.
  564. *
  565. * @private
  566. */
  567. onconnect(id, pid) {
  568. debug("socket connected with id %s", id);
  569. this.id = id;
  570. this.recovered = pid && this._pid === pid;
  571. this._pid = pid; // defined only if connection state recovery is enabled
  572. this.connected = true;
  573. this.emitBuffered();
  574. this.emitReserved("connect");
  575. this._drainQueue(true);
  576. }
  577. /**
  578. * Emit buffered events (received and emitted).
  579. *
  580. * @private
  581. */
  582. emitBuffered() {
  583. this.receiveBuffer.forEach((args) => this.emitEvent(args));
  584. this.receiveBuffer = [];
  585. this.sendBuffer.forEach((packet) => {
  586. this.notifyOutgoingListeners(packet);
  587. this.packet(packet);
  588. });
  589. this.sendBuffer = [];
  590. }
  591. /**
  592. * Called upon server disconnect.
  593. *
  594. * @private
  595. */
  596. ondisconnect() {
  597. debug("server disconnect (%s)", this.nsp);
  598. this.destroy();
  599. this.onclose("io server disconnect");
  600. }
  601. /**
  602. * Called upon forced client/server side disconnections,
  603. * this method ensures the manager stops tracking us and
  604. * that reconnections don't get triggered for this.
  605. *
  606. * @private
  607. */
  608. destroy() {
  609. if (this.subs) {
  610. // clean subscriptions to avoid reconnections
  611. this.subs.forEach((subDestroy) => subDestroy());
  612. this.subs = undefined;
  613. }
  614. this.io["_destroy"](this);
  615. }
  616. /**
  617. * Disconnects the socket manually. In that case, the socket will not try to reconnect.
  618. *
  619. * If this is the last active Socket instance of the {@link Manager}, the low-level connection will be closed.
  620. *
  621. * @example
  622. * const socket = io();
  623. *
  624. * socket.on("disconnect", (reason) => {
  625. * // console.log(reason); prints "io client disconnect"
  626. * });
  627. *
  628. * socket.disconnect();
  629. *
  630. * @return self
  631. */
  632. disconnect() {
  633. if (this.connected) {
  634. debug("performing disconnect (%s)", this.nsp);
  635. this.packet({ type: socket_io_parser_1.PacketType.DISCONNECT });
  636. }
  637. // remove socket from pool
  638. this.destroy();
  639. if (this.connected) {
  640. // fire events
  641. this.onclose("io client disconnect");
  642. }
  643. return this;
  644. }
  645. /**
  646. * Alias for {@link disconnect()}.
  647. *
  648. * @return self
  649. */
  650. close() {
  651. return this.disconnect();
  652. }
  653. /**
  654. * Sets the compress flag.
  655. *
  656. * @example
  657. * socket.compress(false).emit("hello");
  658. *
  659. * @param compress - if `true`, compresses the sending data
  660. * @return self
  661. */
  662. compress(compress) {
  663. this.flags.compress = compress;
  664. return this;
  665. }
  666. /**
  667. * Sets a modifier for a subsequent event emission that the event message will be dropped when this socket is not
  668. * ready to send messages.
  669. *
  670. * @example
  671. * socket.volatile.emit("hello"); // the server may or may not receive it
  672. *
  673. * @returns self
  674. */
  675. get volatile() {
  676. this.flags.volatile = true;
  677. return this;
  678. }
  679. /**
  680. * Sets a modifier for a subsequent event emission that the callback will be called with an error when the
  681. * given number of milliseconds have elapsed without an acknowledgement from the server:
  682. *
  683. * @example
  684. * socket.timeout(5000).emit("my-event", (err) => {
  685. * if (err) {
  686. * // the server did not acknowledge the event in the given delay
  687. * }
  688. * });
  689. *
  690. * @returns self
  691. */
  692. timeout(timeout) {
  693. this.flags.timeout = timeout;
  694. return this;
  695. }
  696. /**
  697. * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
  698. * callback.
  699. *
  700. * @example
  701. * socket.onAny((event, ...args) => {
  702. * console.log(`got ${event}`);
  703. * });
  704. *
  705. * @param listener
  706. */
  707. onAny(listener) {
  708. this._anyListeners = this._anyListeners || [];
  709. this._anyListeners.push(listener);
  710. return this;
  711. }
  712. /**
  713. * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
  714. * callback. The listener is added to the beginning of the listeners array.
  715. *
  716. * @example
  717. * socket.prependAny((event, ...args) => {
  718. * console.log(`got event ${event}`);
  719. * });
  720. *
  721. * @param listener
  722. */
  723. prependAny(listener) {
  724. this._anyListeners = this._anyListeners || [];
  725. this._anyListeners.unshift(listener);
  726. return this;
  727. }
  728. /**
  729. * Removes the listener that will be fired when any event is emitted.
  730. *
  731. * @example
  732. * const catchAllListener = (event, ...args) => {
  733. * console.log(`got event ${event}`);
  734. * }
  735. *
  736. * socket.onAny(catchAllListener);
  737. *
  738. * // remove a specific listener
  739. * socket.offAny(catchAllListener);
  740. *
  741. * // or remove all listeners
  742. * socket.offAny();
  743. *
  744. * @param listener
  745. */
  746. offAny(listener) {
  747. if (!this._anyListeners) {
  748. return this;
  749. }
  750. if (listener) {
  751. const listeners = this._anyListeners;
  752. for (let i = 0; i < listeners.length; i++) {
  753. if (listener === listeners[i]) {
  754. listeners.splice(i, 1);
  755. return this;
  756. }
  757. }
  758. }
  759. else {
  760. this._anyListeners = [];
  761. }
  762. return this;
  763. }
  764. /**
  765. * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
  766. * e.g. to remove listeners.
  767. */
  768. listenersAny() {
  769. return this._anyListeners || [];
  770. }
  771. /**
  772. * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
  773. * callback.
  774. *
  775. * Note: acknowledgements sent to the server are not included.
  776. *
  777. * @example
  778. * socket.onAnyOutgoing((event, ...args) => {
  779. * console.log(`sent event ${event}`);
  780. * });
  781. *
  782. * @param listener
  783. */
  784. onAnyOutgoing(listener) {
  785. this._anyOutgoingListeners = this._anyOutgoingListeners || [];
  786. this._anyOutgoingListeners.push(listener);
  787. return this;
  788. }
  789. /**
  790. * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
  791. * callback. The listener is added to the beginning of the listeners array.
  792. *
  793. * Note: acknowledgements sent to the server are not included.
  794. *
  795. * @example
  796. * socket.prependAnyOutgoing((event, ...args) => {
  797. * console.log(`sent event ${event}`);
  798. * });
  799. *
  800. * @param listener
  801. */
  802. prependAnyOutgoing(listener) {
  803. this._anyOutgoingListeners = this._anyOutgoingListeners || [];
  804. this._anyOutgoingListeners.unshift(listener);
  805. return this;
  806. }
  807. /**
  808. * Removes the listener that will be fired when any event is emitted.
  809. *
  810. * @example
  811. * const catchAllListener = (event, ...args) => {
  812. * console.log(`sent event ${event}`);
  813. * }
  814. *
  815. * socket.onAnyOutgoing(catchAllListener);
  816. *
  817. * // remove a specific listener
  818. * socket.offAnyOutgoing(catchAllListener);
  819. *
  820. * // or remove all listeners
  821. * socket.offAnyOutgoing();
  822. *
  823. * @param [listener] - the catch-all listener (optional)
  824. */
  825. offAnyOutgoing(listener) {
  826. if (!this._anyOutgoingListeners) {
  827. return this;
  828. }
  829. if (listener) {
  830. const listeners = this._anyOutgoingListeners;
  831. for (let i = 0; i < listeners.length; i++) {
  832. if (listener === listeners[i]) {
  833. listeners.splice(i, 1);
  834. return this;
  835. }
  836. }
  837. }
  838. else {
  839. this._anyOutgoingListeners = [];
  840. }
  841. return this;
  842. }
  843. /**
  844. * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
  845. * e.g. to remove listeners.
  846. */
  847. listenersAnyOutgoing() {
  848. return this._anyOutgoingListeners || [];
  849. }
  850. /**
  851. * Notify the listeners for each packet sent
  852. *
  853. * @param packet
  854. *
  855. * @private
  856. */
  857. notifyOutgoingListeners(packet) {
  858. if (this._anyOutgoingListeners && this._anyOutgoingListeners.length) {
  859. const listeners = this._anyOutgoingListeners.slice();
  860. for (const listener of listeners) {
  861. listener.apply(this, packet.data);
  862. }
  863. }
  864. }
  865. }
  866. exports.Socket = Socket;