socket/Controller.js

/**
 * @module flitter-socket/Controller
 */

const ConnectionManager = require('./ConnectionManager')
const LibFlitterController = require('libflitter/controller/Controller')

/**
 * Special class of controller that includes bootstrap methods for
 * using flitter-socket.
 * @class
 * @extends module:libflitter/controller/Controller
 */
class Controller extends LibFlitterController {

    /**
     * Initialize the controller.
     */
    constructor() {
        super()

        /**
         * Map of connection IDs to open connection managers.
         * @type {Object}
         */
        this.connections = {}
    }

    /**
     * Route helper for bootstrapping a transactional websocket connection.
     * Wraps the socket in a new {flitter-socket/ConnectionManager~ConnectionManager} and
     * adds it to this.connections.
     * @param {WebSocket} ws - the incoming websocket
     * @param {express/Request} req - the connection request
     */
    _connect(ws, req){
        const cm = new ConnectionManager(ws, req, this)
        this.connections[cm.id] = cm

        cm.on_close(() => {
            this.connections[cm.id] = undefined
        })
        
        this._client_connected(cm)
    }
    
    /**
     * Send a request to one websocket client.
     * @param {string} endpoint - the endpoint to request data from
     * @param {object} data - the request's body data
     * @param {function} handler - callback function called when a valid client response has been received.
     * @param {string} client_id - connection id to whom the request should be sent.
     */
    _request(endpoint, data, handler, client_id){
        if ( client_id){
            if ( !Object.keys(this.connections).includes(client_id) ) throw new Error('No connection exists with the specified id: '+client_id)
            
            this.connections[client_id]._request(endpoint, data, handler)
        }
    }

    /**
     * Send a request to all connected clients.
     * @param {string} endpoint - the endpoint to request data from
     * @param {object} data - the request's body data
     * @param {function} handler - callback function called each time a client response is received
     */
    _blast(endpoint, data, handler){
        Object.keys(this.connections).forEach(client_id => {
            this._request(endpoint, data, handler, client_id)
        })
    }

    /**
     * Async wrapper for this._request().
     * @param {string} endpoint - the endpoint to request data from
     * @param {object} data - the request's body data
     * @param {string} client_id - connection id to whom the request should be sent.
     */
    _request_async(endpoint, data, client_id){
        return new Promise(resolve => {
            this._request(endpoint, data, (...args) => resolve(...args), client_id)
        })
    }

    /**
     * Called when a new connection manager has been started.
     * @param {module:flitter-socket/ConnectionManager~ConnectionManager} connection_manager
     */
    _client_connected(connection_manager){}
    
}

module.exports = exports = Controller