Source: services/SocketServer/SocketConnection.js

/**
 * Manages socket connections and subscriptions.
 */
class SocketConnection {
    /**
     * Creates an instance of SocketConnection.
     * @param {Object} socket - The socket object representing the connection.
     * @param {Object} serverInstance - The server instance associated with the connection.
     */
    constructor(socket, serverInstance) {
        try {
            /**
             * Returns the server instance associated with the connection.
             * @returns {Object} - The server instance.
             */
            this._serverInstance = () => serverInstance;

            /**
             * The socket object representing the connection.
             * @type {Object}
             */
            this.socket = socket;

            /**
             * Array to store active subscriptions.
             * @type {Array}
             */
            this.subscriptions = [];

            this.init();
        } catch (err) {
            throw new Error.Log(err);
        }
    }

    /**
     * Gets the server instance associated with the connection.
     * @returns {Object} - The server instance.
     */
    get serverInstance() {
        return this._serverInstance();
    }

    /**
     * Initializes socket event listeners and connection status.
     */
    init() {
        this.socket.on('connection:status', this.onConnectionStatus.bind(this));
        this.socket.on('subscribe:doc', this.subscribeDOC.bind(this));
        this.socket.on('subscribe:component', this.subscribeComponent.bind(this));

        /**
         * Object property to store subscribed components.
         * @type {Object}
         */
        this.socket.data.subscribedComponents = {};

        this.emitConnectionStatus();
    }

    /**
     * Handles 'connection:status' event by emitting connection status.
     */
    onConnectionStatus() {
        this.emitConnectionStatus();
    }

    /**
     * Emits connection status to the client.
     */
    emitConnectionStatus() {
        this.socket.emit('connection:status', this.socket.id);
    }

    /**
     * Subscribes to a document based on the provided setup.
     * @param {Object} setup - Configuration options for the document subscription.
     * @returns {Object} - The document subscription instance.
     */
    async subscribeDOC(setup) {
        const { collectionName, filter } = Object(setup);

        try {
            const subs = new DocSubscription({ ...setup }, this.socket);

            this.subscriptions.push(subs);
            const doc = await subs.trigger();

            if (doc) {
                process.on(`socket:update:${collectionName}:${JSON.stringify(filter)}`, () => {
                    subs.trigger().catch(err => {
                        throw new Error.Log(err);
                    });
                });

                this.socket.emit('subscribe:doc:success', doc);
                return subs;
            }
        } catch (err) {
            throw new Error.Log(err);
        }
    }

    /**
     * Subscribes to a component based on the provided setup.
     * @param {Object} setup - Configuration options for the component subscription.
     * @returns {Object} - The component subscription instance.
     */
    async subscribeComponent(setup) {
        const { path, dataDependencies, data, subsUID } = Object(setup);

        try {
            const Component = require('@www/' + path);
            const comp = new Component({ dataDependencies, ...data, subscriptionUID: subsUID });
            const subscription = new ComponentSubscription({ component: comp, subscriptionUID: subsUID }, this);

            if (comp.load) {
                await comp.load();
            }

            comp.dataDependencies.map(item => item.addSocketUpdateListener(this, subscription.subscriptionUID));
            subscription.socket.emit('subscribe:component:success:' + subscription.subscriptionUID, comp.renderToString().toSuccess());
            this.subscriptions.push(subscription);
            return comp;
        } catch (err) {
            this.socket.emit('subscribe:component:error:' + subsUID, new Error.Log(err).response());
        }
    }

    /**
     * Appends a component subscription to the subscribed components list.
     * @param {Object} subscription - The component subscription instance.
     * @returns {Object} - The component object.
     */
    appendComponent(subscription) {
        try {
            if (!subscription.socket) {
                return;
            }

            if (!subscription.socket.data.subscribedComponents) {
                subscription.socket.data.subscribedComponents = {};
            }

            subscription.socket.data.subscribedComponents[subscription.subscriptionUID] = subscription.component;
            return subscription.component;
        } catch (err) {
            throw new Error.Log(err);
        }
    }

    /**
     * Gets the component object associated with the provided subscription UID.
     * @param {string} subscriptionUID - The unique identifier for the component subscription.
     * @returns {Object} - The component object.
     */
    getComponent(subscriptionUID) {
        try {
            if (!this.socket || !this.socket.data.subscribedComponents) {
                return;
            }

            return this.socket.data.subscribedComponents[subscriptionUID];
        } catch (err) {
            throw new Error.Log(err);
        }
    }

    /**
     * Gets the subscription object associated with the provided subscription UID.
     * @param {string} subscriptionUID - The unique identifier for the subscription.
     * @returns {Object} - The subscription object.
     */
    getSubscription(subscriptionUID) {
        try {
            if (!this.socket || !this.subscriptions) {
                return;
            }

            return this.subscriptions.find(item => item.subscriptionUID === subscriptionUID);
        } catch (err) {
            throw new Error.Log(err);
        }
    }

    /**
     * Updates the component associated with the provided subscription UID using merge data.
     * @param {string} subscriptionUID - The unique identifier for the component subscription.
     * @param {Object} mergeData - The data used for merging and updating the component.
     * @returns {Object} - The updated component object.
     */
    updateComponent(subscriptionUID, mergeData) {
        try {
            const component = this.socket.data.subscribedComponents[subscriptionUID];

            component.updateMerge(mergeData);
            const stringHTML = component.renderToString();

            this.socket.emit('subscribe:component:data:' + subscriptionUID, stringHTML.toSuccess());
            return component;
        } catch (err) {
            throw new Error.Log(err);
        }
    }
}

module.exports = SocketConnection;