 85bf1341f3
			
		
	
	85bf1341f3
	
	
	
		
			
			Frontend Enhancements: - Complete React TypeScript frontend with modern UI components - Distributed workflows management interface with real-time updates - Socket.IO integration for live agent status monitoring - Agent management dashboard with cluster visualization - Project management interface with metrics and task tracking - Responsive design with proper error handling and loading states Backend Infrastructure: - Distributed coordinator for multi-agent workflow orchestration - Cluster management API with comprehensive agent operations - Enhanced database models for agents and projects - Project service for filesystem-based project discovery - Performance monitoring and metrics collection - Comprehensive API documentation and error handling Documentation: - Complete distributed development guide (README_DISTRIBUTED.md) - Comprehensive development report with architecture insights - System configuration templates and deployment guides The platform now provides a complete web interface for managing the distributed AI cluster with real-time monitoring, workflow orchestration, and agent coordination capabilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			904 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			904 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { PacketType } from "socket.io-parser";
 | |
| import { on } from "./on.js";
 | |
| import { Emitter, } from "@socket.io/component-emitter";
 | |
| import debugModule from "debug"; // debug()
 | |
| const debug = debugModule("socket.io-client:socket"); // debug()
 | |
| /**
 | |
|  * Internal events.
 | |
|  * These events can't be emitted by the user.
 | |
|  */
 | |
| const RESERVED_EVENTS = Object.freeze({
 | |
|     connect: 1,
 | |
|     connect_error: 1,
 | |
|     disconnect: 1,
 | |
|     disconnecting: 1,
 | |
|     // EventEmitter reserved events: https://nodejs.org/api/events.html#events_event_newlistener
 | |
|     newListener: 1,
 | |
|     removeListener: 1,
 | |
| });
 | |
| /**
 | |
|  * A Socket is the fundamental class for interacting with the server.
 | |
|  *
 | |
|  * A Socket belongs to a certain Namespace (by default /) and uses an underlying {@link Manager} to communicate.
 | |
|  *
 | |
|  * @example
 | |
|  * const socket = io();
 | |
|  *
 | |
|  * socket.on("connect", () => {
 | |
|  *   console.log("connected");
 | |
|  * });
 | |
|  *
 | |
|  * // send an event to the server
 | |
|  * socket.emit("foo", "bar");
 | |
|  *
 | |
|  * socket.on("foobar", () => {
 | |
|  *   // an event was received from the server
 | |
|  * });
 | |
|  *
 | |
|  * // upon disconnection
 | |
|  * socket.on("disconnect", (reason) => {
 | |
|  *   console.log(`disconnected due to ${reason}`);
 | |
|  * });
 | |
|  */
 | |
| export class Socket extends Emitter {
 | |
|     /**
 | |
|      * `Socket` constructor.
 | |
|      */
 | |
|     constructor(io, nsp, opts) {
 | |
|         super();
 | |
|         /**
 | |
|          * Whether the socket is currently connected to the server.
 | |
|          *
 | |
|          * @example
 | |
|          * const socket = io();
 | |
|          *
 | |
|          * socket.on("connect", () => {
 | |
|          *   console.log(socket.connected); // true
 | |
|          * });
 | |
|          *
 | |
|          * socket.on("disconnect", () => {
 | |
|          *   console.log(socket.connected); // false
 | |
|          * });
 | |
|          */
 | |
|         this.connected = false;
 | |
|         /**
 | |
|          * Whether the connection state was recovered after a temporary disconnection. In that case, any missed packets will
 | |
|          * be transmitted by the server.
 | |
|          */
 | |
|         this.recovered = false;
 | |
|         /**
 | |
|          * Buffer for packets received before the CONNECT packet
 | |
|          */
 | |
|         this.receiveBuffer = [];
 | |
|         /**
 | |
|          * Buffer for packets that will be sent once the socket is connected
 | |
|          */
 | |
|         this.sendBuffer = [];
 | |
|         /**
 | |
|          * The queue of packets to be sent with retry in case of failure.
 | |
|          *
 | |
|          * Packets are sent one by one, each waiting for the server acknowledgement, in order to guarantee the delivery order.
 | |
|          * @private
 | |
|          */
 | |
|         this._queue = [];
 | |
|         /**
 | |
|          * A sequence to generate the ID of the {@link QueuedPacket}.
 | |
|          * @private
 | |
|          */
 | |
|         this._queueSeq = 0;
 | |
|         this.ids = 0;
 | |
|         /**
 | |
|          * A map containing acknowledgement handlers.
 | |
|          *
 | |
|          * The `withError` attribute is used to differentiate handlers that accept an error as first argument:
 | |
|          *
 | |
|          * - `socket.emit("test", (err, value) => { ... })` with `ackTimeout` option
 | |
|          * - `socket.timeout(5000).emit("test", (err, value) => { ... })`
 | |
|          * - `const value = await socket.emitWithAck("test")`
 | |
|          *
 | |
|          * From those that don't:
 | |
|          *
 | |
|          * - `socket.emit("test", (value) => { ... });`
 | |
|          *
 | |
|          * In the first case, the handlers will be called with an error when:
 | |
|          *
 | |
|          * - the timeout is reached
 | |
|          * - the socket gets disconnected
 | |
|          *
 | |
|          * In the second case, the handlers will be simply discarded upon disconnection, since the client will never receive
 | |
|          * an acknowledgement from the server.
 | |
|          *
 | |
|          * @private
 | |
|          */
 | |
|         this.acks = {};
 | |
|         this.flags = {};
 | |
|         this.io = io;
 | |
|         this.nsp = nsp;
 | |
|         if (opts && opts.auth) {
 | |
|             this.auth = opts.auth;
 | |
|         }
 | |
|         this._opts = Object.assign({}, opts);
 | |
|         if (this.io._autoConnect)
 | |
|             this.open();
 | |
|     }
 | |
|     /**
 | |
|      * Whether the socket is currently disconnected
 | |
|      *
 | |
|      * @example
 | |
|      * const socket = io();
 | |
|      *
 | |
|      * socket.on("connect", () => {
 | |
|      *   console.log(socket.disconnected); // false
 | |
|      * });
 | |
|      *
 | |
|      * socket.on("disconnect", () => {
 | |
|      *   console.log(socket.disconnected); // true
 | |
|      * });
 | |
|      */
 | |
|     get disconnected() {
 | |
|         return !this.connected;
 | |
|     }
 | |
|     /**
 | |
|      * Subscribe to open, close and packet events
 | |
|      *
 | |
|      * @private
 | |
|      */
 | |
|     subEvents() {
 | |
|         if (this.subs)
 | |
|             return;
 | |
|         const io = this.io;
 | |
|         this.subs = [
 | |
|             on(io, "open", this.onopen.bind(this)),
 | |
|             on(io, "packet", this.onpacket.bind(this)),
 | |
|             on(io, "error", this.onerror.bind(this)),
 | |
|             on(io, "close", this.onclose.bind(this)),
 | |
|         ];
 | |
|     }
 | |
|     /**
 | |
|      * Whether the Socket will try to reconnect when its Manager connects or reconnects.
 | |
|      *
 | |
|      * @example
 | |
|      * const socket = io();
 | |
|      *
 | |
|      * console.log(socket.active); // true
 | |
|      *
 | |
|      * socket.on("disconnect", (reason) => {
 | |
|      *   if (reason === "io server disconnect") {
 | |
|      *     // the disconnection was initiated by the server, you need to manually reconnect
 | |
|      *     console.log(socket.active); // false
 | |
|      *   }
 | |
|      *   // else the socket will automatically try to reconnect
 | |
|      *   console.log(socket.active); // true
 | |
|      * });
 | |
|      */
 | |
|     get active() {
 | |
|         return !!this.subs;
 | |
|     }
 | |
|     /**
 | |
|      * "Opens" the socket.
 | |
|      *
 | |
|      * @example
 | |
|      * const socket = io({
 | |
|      *   autoConnect: false
 | |
|      * });
 | |
|      *
 | |
|      * socket.connect();
 | |
|      */
 | |
|     connect() {
 | |
|         if (this.connected)
 | |
|             return this;
 | |
|         this.subEvents();
 | |
|         if (!this.io["_reconnecting"])
 | |
|             this.io.open(); // ensure open
 | |
|         if ("open" === this.io._readyState)
 | |
|             this.onopen();
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Alias for {@link connect()}.
 | |
|      */
 | |
|     open() {
 | |
|         return this.connect();
 | |
|     }
 | |
|     /**
 | |
|      * Sends a `message` event.
 | |
|      *
 | |
|      * This method mimics the WebSocket.send() method.
 | |
|      *
 | |
|      * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
 | |
|      *
 | |
|      * @example
 | |
|      * socket.send("hello");
 | |
|      *
 | |
|      * // this is equivalent to
 | |
|      * socket.emit("message", "hello");
 | |
|      *
 | |
|      * @return self
 | |
|      */
 | |
|     send(...args) {
 | |
|         args.unshift("message");
 | |
|         this.emit.apply(this, args);
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Override `emit`.
 | |
|      * If the event is in `events`, it's emitted normally.
 | |
|      *
 | |
|      * @example
 | |
|      * socket.emit("hello", "world");
 | |
|      *
 | |
|      * // all serializable datastructures are supported (no need to call JSON.stringify)
 | |
|      * socket.emit("hello", 1, "2", { 3: ["4"], 5: Uint8Array.from([6]) });
 | |
|      *
 | |
|      * // with an acknowledgement from the server
 | |
|      * socket.emit("hello", "world", (val) => {
 | |
|      *   // ...
 | |
|      * });
 | |
|      *
 | |
|      * @return self
 | |
|      */
 | |
|     emit(ev, ...args) {
 | |
|         var _a, _b, _c;
 | |
|         if (RESERVED_EVENTS.hasOwnProperty(ev)) {
 | |
|             throw new Error('"' + ev.toString() + '" is a reserved event name');
 | |
|         }
 | |
|         args.unshift(ev);
 | |
|         if (this._opts.retries && !this.flags.fromQueue && !this.flags.volatile) {
 | |
|             this._addToQueue(args);
 | |
|             return this;
 | |
|         }
 | |
|         const packet = {
 | |
|             type: PacketType.EVENT,
 | |
|             data: args,
 | |
|         };
 | |
|         packet.options = {};
 | |
|         packet.options.compress = this.flags.compress !== false;
 | |
|         // event ack callback
 | |
|         if ("function" === typeof args[args.length - 1]) {
 | |
|             const id = this.ids++;
 | |
|             debug("emitting packet with ack id %d", id);
 | |
|             const ack = args.pop();
 | |
|             this._registerAckCallback(id, ack);
 | |
|             packet.id = id;
 | |
|         }
 | |
|         const isTransportWritable = (_b = (_a = this.io.engine) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.writable;
 | |
|         const isConnected = this.connected && !((_c = this.io.engine) === null || _c === void 0 ? void 0 : _c._hasPingExpired());
 | |
|         const discardPacket = this.flags.volatile && !isTransportWritable;
 | |
|         if (discardPacket) {
 | |
|             debug("discard packet as the transport is not currently writable");
 | |
|         }
 | |
|         else if (isConnected) {
 | |
|             this.notifyOutgoingListeners(packet);
 | |
|             this.packet(packet);
 | |
|         }
 | |
|         else {
 | |
|             this.sendBuffer.push(packet);
 | |
|         }
 | |
|         this.flags = {};
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * @private
 | |
|      */
 | |
|     _registerAckCallback(id, ack) {
 | |
|         var _a;
 | |
|         const timeout = (_a = this.flags.timeout) !== null && _a !== void 0 ? _a : this._opts.ackTimeout;
 | |
|         if (timeout === undefined) {
 | |
|             this.acks[id] = ack;
 | |
|             return;
 | |
|         }
 | |
|         // @ts-ignore
 | |
|         const timer = this.io.setTimeoutFn(() => {
 | |
|             delete this.acks[id];
 | |
|             for (let i = 0; i < this.sendBuffer.length; i++) {
 | |
|                 if (this.sendBuffer[i].id === id) {
 | |
|                     debug("removing packet with ack id %d from the buffer", id);
 | |
|                     this.sendBuffer.splice(i, 1);
 | |
|                 }
 | |
|             }
 | |
|             debug("event with ack id %d has timed out after %d ms", id, timeout);
 | |
|             ack.call(this, new Error("operation has timed out"));
 | |
|         }, timeout);
 | |
|         const fn = (...args) => {
 | |
|             // @ts-ignore
 | |
|             this.io.clearTimeoutFn(timer);
 | |
|             ack.apply(this, args);
 | |
|         };
 | |
|         fn.withError = true;
 | |
|         this.acks[id] = fn;
 | |
|     }
 | |
|     /**
 | |
|      * Emits an event and waits for an acknowledgement
 | |
|      *
 | |
|      * @example
 | |
|      * // without timeout
 | |
|      * const response = await socket.emitWithAck("hello", "world");
 | |
|      *
 | |
|      * // with a specific timeout
 | |
|      * try {
 | |
|      *   const response = await socket.timeout(1000).emitWithAck("hello", "world");
 | |
|      * } catch (err) {
 | |
|      *   // the server did not acknowledge the event in the given delay
 | |
|      * }
 | |
|      *
 | |
|      * @return a Promise that will be fulfilled when the server acknowledges the event
 | |
|      */
 | |
|     emitWithAck(ev, ...args) {
 | |
|         return new Promise((resolve, reject) => {
 | |
|             const fn = (arg1, arg2) => {
 | |
|                 return arg1 ? reject(arg1) : resolve(arg2);
 | |
|             };
 | |
|             fn.withError = true;
 | |
|             args.push(fn);
 | |
|             this.emit(ev, ...args);
 | |
|         });
 | |
|     }
 | |
|     /**
 | |
|      * Add the packet to the queue.
 | |
|      * @param args
 | |
|      * @private
 | |
|      */
 | |
|     _addToQueue(args) {
 | |
|         let ack;
 | |
|         if (typeof args[args.length - 1] === "function") {
 | |
|             ack = args.pop();
 | |
|         }
 | |
|         const packet = {
 | |
|             id: this._queueSeq++,
 | |
|             tryCount: 0,
 | |
|             pending: false,
 | |
|             args,
 | |
|             flags: Object.assign({ fromQueue: true }, this.flags),
 | |
|         };
 | |
|         args.push((err, ...responseArgs) => {
 | |
|             if (packet !== this._queue[0]) {
 | |
|                 // the packet has already been acknowledged
 | |
|                 return;
 | |
|             }
 | |
|             const hasError = err !== null;
 | |
|             if (hasError) {
 | |
|                 if (packet.tryCount > this._opts.retries) {
 | |
|                     debug("packet [%d] is discarded after %d tries", packet.id, packet.tryCount);
 | |
|                     this._queue.shift();
 | |
|                     if (ack) {
 | |
|                         ack(err);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else {
 | |
|                 debug("packet [%d] was successfully sent", packet.id);
 | |
|                 this._queue.shift();
 | |
|                 if (ack) {
 | |
|                     ack(null, ...responseArgs);
 | |
|                 }
 | |
|             }
 | |
|             packet.pending = false;
 | |
|             return this._drainQueue();
 | |
|         });
 | |
|         this._queue.push(packet);
 | |
|         this._drainQueue();
 | |
|     }
 | |
|     /**
 | |
|      * Send the first packet of the queue, and wait for an acknowledgement from the server.
 | |
|      * @param force - whether to resend a packet that has not been acknowledged yet
 | |
|      *
 | |
|      * @private
 | |
|      */
 | |
|     _drainQueue(force = false) {
 | |
|         debug("draining queue");
 | |
|         if (!this.connected || this._queue.length === 0) {
 | |
|             return;
 | |
|         }
 | |
|         const packet = this._queue[0];
 | |
|         if (packet.pending && !force) {
 | |
|             debug("packet [%d] has already been sent and is waiting for an ack", packet.id);
 | |
|             return;
 | |
|         }
 | |
|         packet.pending = true;
 | |
|         packet.tryCount++;
 | |
|         debug("sending packet [%d] (try n°%d)", packet.id, packet.tryCount);
 | |
|         this.flags = packet.flags;
 | |
|         this.emit.apply(this, packet.args);
 | |
|     }
 | |
|     /**
 | |
|      * Sends a packet.
 | |
|      *
 | |
|      * @param packet
 | |
|      * @private
 | |
|      */
 | |
|     packet(packet) {
 | |
|         packet.nsp = this.nsp;
 | |
|         this.io._packet(packet);
 | |
|     }
 | |
|     /**
 | |
|      * Called upon engine `open`.
 | |
|      *
 | |
|      * @private
 | |
|      */
 | |
|     onopen() {
 | |
|         debug("transport is open - connecting");
 | |
|         if (typeof this.auth == "function") {
 | |
|             this.auth((data) => {
 | |
|                 this._sendConnectPacket(data);
 | |
|             });
 | |
|         }
 | |
|         else {
 | |
|             this._sendConnectPacket(this.auth);
 | |
|         }
 | |
|     }
 | |
|     /**
 | |
|      * Sends a CONNECT packet to initiate the Socket.IO session.
 | |
|      *
 | |
|      * @param data
 | |
|      * @private
 | |
|      */
 | |
|     _sendConnectPacket(data) {
 | |
|         this.packet({
 | |
|             type: PacketType.CONNECT,
 | |
|             data: this._pid
 | |
|                 ? Object.assign({ pid: this._pid, offset: this._lastOffset }, data)
 | |
|                 : data,
 | |
|         });
 | |
|     }
 | |
|     /**
 | |
|      * Called upon engine or manager `error`.
 | |
|      *
 | |
|      * @param err
 | |
|      * @private
 | |
|      */
 | |
|     onerror(err) {
 | |
|         if (!this.connected) {
 | |
|             this.emitReserved("connect_error", err);
 | |
|         }
 | |
|     }
 | |
|     /**
 | |
|      * Called upon engine `close`.
 | |
|      *
 | |
|      * @param reason
 | |
|      * @param description
 | |
|      * @private
 | |
|      */
 | |
|     onclose(reason, description) {
 | |
|         debug("close (%s)", reason);
 | |
|         this.connected = false;
 | |
|         delete this.id;
 | |
|         this.emitReserved("disconnect", reason, description);
 | |
|         this._clearAcks();
 | |
|     }
 | |
|     /**
 | |
|      * Clears the acknowledgement handlers upon disconnection, since the client will never receive an acknowledgement from
 | |
|      * the server.
 | |
|      *
 | |
|      * @private
 | |
|      */
 | |
|     _clearAcks() {
 | |
|         Object.keys(this.acks).forEach((id) => {
 | |
|             const isBuffered = this.sendBuffer.some((packet) => String(packet.id) === id);
 | |
|             if (!isBuffered) {
 | |
|                 // note: handlers that do not accept an error as first argument are ignored here
 | |
|                 const ack = this.acks[id];
 | |
|                 delete this.acks[id];
 | |
|                 if (ack.withError) {
 | |
|                     ack.call(this, new Error("socket has been disconnected"));
 | |
|                 }
 | |
|             }
 | |
|         });
 | |
|     }
 | |
|     /**
 | |
|      * Called with socket packet.
 | |
|      *
 | |
|      * @param packet
 | |
|      * @private
 | |
|      */
 | |
|     onpacket(packet) {
 | |
|         const sameNamespace = packet.nsp === this.nsp;
 | |
|         if (!sameNamespace)
 | |
|             return;
 | |
|         switch (packet.type) {
 | |
|             case PacketType.CONNECT:
 | |
|                 if (packet.data && packet.data.sid) {
 | |
|                     this.onconnect(packet.data.sid, packet.data.pid);
 | |
|                 }
 | |
|                 else {
 | |
|                     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/)"));
 | |
|                 }
 | |
|                 break;
 | |
|             case PacketType.EVENT:
 | |
|             case PacketType.BINARY_EVENT:
 | |
|                 this.onevent(packet);
 | |
|                 break;
 | |
|             case PacketType.ACK:
 | |
|             case PacketType.BINARY_ACK:
 | |
|                 this.onack(packet);
 | |
|                 break;
 | |
|             case PacketType.DISCONNECT:
 | |
|                 this.ondisconnect();
 | |
|                 break;
 | |
|             case PacketType.CONNECT_ERROR:
 | |
|                 this.destroy();
 | |
|                 const err = new Error(packet.data.message);
 | |
|                 // @ts-ignore
 | |
|                 err.data = packet.data.data;
 | |
|                 this.emitReserved("connect_error", err);
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
|     /**
 | |
|      * Called upon a server event.
 | |
|      *
 | |
|      * @param packet
 | |
|      * @private
 | |
|      */
 | |
|     onevent(packet) {
 | |
|         const args = packet.data || [];
 | |
|         debug("emitting event %j", args);
 | |
|         if (null != packet.id) {
 | |
|             debug("attaching ack callback to event");
 | |
|             args.push(this.ack(packet.id));
 | |
|         }
 | |
|         if (this.connected) {
 | |
|             this.emitEvent(args);
 | |
|         }
 | |
|         else {
 | |
|             this.receiveBuffer.push(Object.freeze(args));
 | |
|         }
 | |
|     }
 | |
|     emitEvent(args) {
 | |
|         if (this._anyListeners && this._anyListeners.length) {
 | |
|             const listeners = this._anyListeners.slice();
 | |
|             for (const listener of listeners) {
 | |
|                 listener.apply(this, args);
 | |
|             }
 | |
|         }
 | |
|         super.emit.apply(this, args);
 | |
|         if (this._pid && args.length && typeof args[args.length - 1] === "string") {
 | |
|             this._lastOffset = args[args.length - 1];
 | |
|         }
 | |
|     }
 | |
|     /**
 | |
|      * Produces an ack callback to emit with an event.
 | |
|      *
 | |
|      * @private
 | |
|      */
 | |
|     ack(id) {
 | |
|         const self = this;
 | |
|         let sent = false;
 | |
|         return function (...args) {
 | |
|             // prevent double callbacks
 | |
|             if (sent)
 | |
|                 return;
 | |
|             sent = true;
 | |
|             debug("sending ack %j", args);
 | |
|             self.packet({
 | |
|                 type: PacketType.ACK,
 | |
|                 id: id,
 | |
|                 data: args,
 | |
|             });
 | |
|         };
 | |
|     }
 | |
|     /**
 | |
|      * Called upon a server acknowledgement.
 | |
|      *
 | |
|      * @param packet
 | |
|      * @private
 | |
|      */
 | |
|     onack(packet) {
 | |
|         const ack = this.acks[packet.id];
 | |
|         if (typeof ack !== "function") {
 | |
|             debug("bad ack %s", packet.id);
 | |
|             return;
 | |
|         }
 | |
|         delete this.acks[packet.id];
 | |
|         debug("calling ack %s with %j", packet.id, packet.data);
 | |
|         // @ts-ignore FIXME ack is incorrectly inferred as 'never'
 | |
|         if (ack.withError) {
 | |
|             packet.data.unshift(null);
 | |
|         }
 | |
|         // @ts-ignore
 | |
|         ack.apply(this, packet.data);
 | |
|     }
 | |
|     /**
 | |
|      * Called upon server connect.
 | |
|      *
 | |
|      * @private
 | |
|      */
 | |
|     onconnect(id, pid) {
 | |
|         debug("socket connected with id %s", id);
 | |
|         this.id = id;
 | |
|         this.recovered = pid && this._pid === pid;
 | |
|         this._pid = pid; // defined only if connection state recovery is enabled
 | |
|         this.connected = true;
 | |
|         this.emitBuffered();
 | |
|         this.emitReserved("connect");
 | |
|         this._drainQueue(true);
 | |
|     }
 | |
|     /**
 | |
|      * Emit buffered events (received and emitted).
 | |
|      *
 | |
|      * @private
 | |
|      */
 | |
|     emitBuffered() {
 | |
|         this.receiveBuffer.forEach((args) => this.emitEvent(args));
 | |
|         this.receiveBuffer = [];
 | |
|         this.sendBuffer.forEach((packet) => {
 | |
|             this.notifyOutgoingListeners(packet);
 | |
|             this.packet(packet);
 | |
|         });
 | |
|         this.sendBuffer = [];
 | |
|     }
 | |
|     /**
 | |
|      * Called upon server disconnect.
 | |
|      *
 | |
|      * @private
 | |
|      */
 | |
|     ondisconnect() {
 | |
|         debug("server disconnect (%s)", this.nsp);
 | |
|         this.destroy();
 | |
|         this.onclose("io server disconnect");
 | |
|     }
 | |
|     /**
 | |
|      * Called upon forced client/server side disconnections,
 | |
|      * this method ensures the manager stops tracking us and
 | |
|      * that reconnections don't get triggered for this.
 | |
|      *
 | |
|      * @private
 | |
|      */
 | |
|     destroy() {
 | |
|         if (this.subs) {
 | |
|             // clean subscriptions to avoid reconnections
 | |
|             this.subs.forEach((subDestroy) => subDestroy());
 | |
|             this.subs = undefined;
 | |
|         }
 | |
|         this.io["_destroy"](this);
 | |
|     }
 | |
|     /**
 | |
|      * Disconnects the socket manually. In that case, the socket will not try to reconnect.
 | |
|      *
 | |
|      * If this is the last active Socket instance of the {@link Manager}, the low-level connection will be closed.
 | |
|      *
 | |
|      * @example
 | |
|      * const socket = io();
 | |
|      *
 | |
|      * socket.on("disconnect", (reason) => {
 | |
|      *   // console.log(reason); prints "io client disconnect"
 | |
|      * });
 | |
|      *
 | |
|      * socket.disconnect();
 | |
|      *
 | |
|      * @return self
 | |
|      */
 | |
|     disconnect() {
 | |
|         if (this.connected) {
 | |
|             debug("performing disconnect (%s)", this.nsp);
 | |
|             this.packet({ type: PacketType.DISCONNECT });
 | |
|         }
 | |
|         // remove socket from pool
 | |
|         this.destroy();
 | |
|         if (this.connected) {
 | |
|             // fire events
 | |
|             this.onclose("io client disconnect");
 | |
|         }
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Alias for {@link disconnect()}.
 | |
|      *
 | |
|      * @return self
 | |
|      */
 | |
|     close() {
 | |
|         return this.disconnect();
 | |
|     }
 | |
|     /**
 | |
|      * Sets the compress flag.
 | |
|      *
 | |
|      * @example
 | |
|      * socket.compress(false).emit("hello");
 | |
|      *
 | |
|      * @param compress - if `true`, compresses the sending data
 | |
|      * @return self
 | |
|      */
 | |
|     compress(compress) {
 | |
|         this.flags.compress = compress;
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Sets a modifier for a subsequent event emission that the event message will be dropped when this socket is not
 | |
|      * ready to send messages.
 | |
|      *
 | |
|      * @example
 | |
|      * socket.volatile.emit("hello"); // the server may or may not receive it
 | |
|      *
 | |
|      * @returns self
 | |
|      */
 | |
|     get volatile() {
 | |
|         this.flags.volatile = true;
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Sets a modifier for a subsequent event emission that the callback will be called with an error when the
 | |
|      * given number of milliseconds have elapsed without an acknowledgement from the server:
 | |
|      *
 | |
|      * @example
 | |
|      * socket.timeout(5000).emit("my-event", (err) => {
 | |
|      *   if (err) {
 | |
|      *     // the server did not acknowledge the event in the given delay
 | |
|      *   }
 | |
|      * });
 | |
|      *
 | |
|      * @returns self
 | |
|      */
 | |
|     timeout(timeout) {
 | |
|         this.flags.timeout = timeout;
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | |
|      * callback.
 | |
|      *
 | |
|      * @example
 | |
|      * socket.onAny((event, ...args) => {
 | |
|      *   console.log(`got ${event}`);
 | |
|      * });
 | |
|      *
 | |
|      * @param listener
 | |
|      */
 | |
|     onAny(listener) {
 | |
|         this._anyListeners = this._anyListeners || [];
 | |
|         this._anyListeners.push(listener);
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | |
|      * callback. The listener is added to the beginning of the listeners array.
 | |
|      *
 | |
|      * @example
 | |
|      * socket.prependAny((event, ...args) => {
 | |
|      *   console.log(`got event ${event}`);
 | |
|      * });
 | |
|      *
 | |
|      * @param listener
 | |
|      */
 | |
|     prependAny(listener) {
 | |
|         this._anyListeners = this._anyListeners || [];
 | |
|         this._anyListeners.unshift(listener);
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Removes the listener that will be fired when any event is emitted.
 | |
|      *
 | |
|      * @example
 | |
|      * const catchAllListener = (event, ...args) => {
 | |
|      *   console.log(`got event ${event}`);
 | |
|      * }
 | |
|      *
 | |
|      * socket.onAny(catchAllListener);
 | |
|      *
 | |
|      * // remove a specific listener
 | |
|      * socket.offAny(catchAllListener);
 | |
|      *
 | |
|      * // or remove all listeners
 | |
|      * socket.offAny();
 | |
|      *
 | |
|      * @param listener
 | |
|      */
 | |
|     offAny(listener) {
 | |
|         if (!this._anyListeners) {
 | |
|             return this;
 | |
|         }
 | |
|         if (listener) {
 | |
|             const listeners = this._anyListeners;
 | |
|             for (let i = 0; i < listeners.length; i++) {
 | |
|                 if (listener === listeners[i]) {
 | |
|                     listeners.splice(i, 1);
 | |
|                     return this;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             this._anyListeners = [];
 | |
|         }
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
 | |
|      * e.g. to remove listeners.
 | |
|      */
 | |
|     listenersAny() {
 | |
|         return this._anyListeners || [];
 | |
|     }
 | |
|     /**
 | |
|      * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | |
|      * callback.
 | |
|      *
 | |
|      * Note: acknowledgements sent to the server are not included.
 | |
|      *
 | |
|      * @example
 | |
|      * socket.onAnyOutgoing((event, ...args) => {
 | |
|      *   console.log(`sent event ${event}`);
 | |
|      * });
 | |
|      *
 | |
|      * @param listener
 | |
|      */
 | |
|     onAnyOutgoing(listener) {
 | |
|         this._anyOutgoingListeners = this._anyOutgoingListeners || [];
 | |
|         this._anyOutgoingListeners.push(listener);
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | |
|      * callback. The listener is added to the beginning of the listeners array.
 | |
|      *
 | |
|      * Note: acknowledgements sent to the server are not included.
 | |
|      *
 | |
|      * @example
 | |
|      * socket.prependAnyOutgoing((event, ...args) => {
 | |
|      *   console.log(`sent event ${event}`);
 | |
|      * });
 | |
|      *
 | |
|      * @param listener
 | |
|      */
 | |
|     prependAnyOutgoing(listener) {
 | |
|         this._anyOutgoingListeners = this._anyOutgoingListeners || [];
 | |
|         this._anyOutgoingListeners.unshift(listener);
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Removes the listener that will be fired when any event is emitted.
 | |
|      *
 | |
|      * @example
 | |
|      * const catchAllListener = (event, ...args) => {
 | |
|      *   console.log(`sent event ${event}`);
 | |
|      * }
 | |
|      *
 | |
|      * socket.onAnyOutgoing(catchAllListener);
 | |
|      *
 | |
|      * // remove a specific listener
 | |
|      * socket.offAnyOutgoing(catchAllListener);
 | |
|      *
 | |
|      * // or remove all listeners
 | |
|      * socket.offAnyOutgoing();
 | |
|      *
 | |
|      * @param [listener] - the catch-all listener (optional)
 | |
|      */
 | |
|     offAnyOutgoing(listener) {
 | |
|         if (!this._anyOutgoingListeners) {
 | |
|             return this;
 | |
|         }
 | |
|         if (listener) {
 | |
|             const listeners = this._anyOutgoingListeners;
 | |
|             for (let i = 0; i < listeners.length; i++) {
 | |
|                 if (listener === listeners[i]) {
 | |
|                     listeners.splice(i, 1);
 | |
|                     return this;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             this._anyOutgoingListeners = [];
 | |
|         }
 | |
|         return this;
 | |
|     }
 | |
|     /**
 | |
|      * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
 | |
|      * e.g. to remove listeners.
 | |
|      */
 | |
|     listenersAnyOutgoing() {
 | |
|         return this._anyOutgoingListeners || [];
 | |
|     }
 | |
|     /**
 | |
|      * Notify the listeners for each packet sent
 | |
|      *
 | |
|      * @param packet
 | |
|      *
 | |
|      * @private
 | |
|      */
 | |
|     notifyOutgoingListeners(packet) {
 | |
|         if (this._anyOutgoingListeners && this._anyOutgoingListeners.length) {
 | |
|             const listeners = this._anyOutgoingListeners.slice();
 | |
|             for (const listener of listeners) {
 | |
|                 listener.apply(this, packet.data);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |