Repository

js/Mobilizing/net/Storage.js

import EventEmitter from "../core/util/EventEmitter";

/**
* Fired when the client successfully connects to the server
* @event connect
*/
const EVT_CONNECT = "connect";

/**
* Fired when the client disconnects from the server
* @event disconnect
*/
const EVT_DISCONNECT = "disconnect";

/**
* Fired when a connection error occurs
* @event error
*/
const EVT_ERROR = "error";

/**
* Fired when a connection times out
* @event connect_timeout
*/
const EVT_CONNECT_TIMEOUT = "connect_timeout";

/**
* Storage is a client for the Storage server
* It allows remote persistant storage
* A runing instance of the Storage server is required to make this work
*
* @example
*    //@TODO
*/
export default class Storage {
    /**
    * @param {Object} params Parameters object, given by the constructor.
    * @param {String} params.url The URL of the server on which the MobilizingServer instance is running
    * @param {Boolean} [params.autoConnect=true] Whether the connection should be automatically opened
    */
    constructor({
        url = "",
        autoConnect = true
    } = {}) {
        this.url = url;
        this.autoConnect = autoConnect;

        this.id = null;
        this.events = new EventEmitter({ "scope": this });

        if (this.autoConnect) {
            this.open(this.url);
        }
    }

    /**
    * Open the socket connection

    * @param {String} url URL of the Storage server instance
    */
    open(url) {
        if (!("io" in window)) {
            const script = document.createElement("script");
            script.src = `${url}/socket.io/socket.io.js`;
            script.onload = () => {
                this.open(url);
            };
            script.onerror = (error) => {
                this.events.trigger(EVT_ERROR, error);
            };

            document.head.appendChild(script);
        }
        else {
            this.socket = window.io.connect(url);

            this.socket.on("connect", () => {
                this.id = this.socket.io.engine.id;

                this.socket.on("disconnect", () => {
                    this.events.trigger(EVT_DISCONNECT);
                });

                this.events.trigger(EVT_CONNECT);
            });

            this.socket.on("error", (error) => {
                this.events.trigger(EVT_ERROR, error);
            });

            this.socket.on("connect_timeout", (timeout) => {
                this.events.trigger(EVT_CONNECT_TIMEOUT, timeout);
            });
        }
    }

    /**
    * Close the socket connection
    * @method close
    */
    close() {
        if (this.socket) {
            this.socket.disconnect();
            delete this.socket;
        }
    }

    /**
    * Lists available collections

    * @param {Function} callback The callback to invoke with the list of collection names
    */
    listCollections(/*callback*/) {
        if (this.socket) {
            this.socket.emit("/collections/list", ...arguments);
        }
    }

    /**
    * Adds a new collection

    * @param {String} name The collection"s name
    * @param {Object} options Options used for the creation; see https://rawgit.com/techfort/LokiJS/master/jsdoc/Loki.html#addCollection
    * @param {Function} callback The callback to invoke with the new collection name
    */
    addCollection(/*name, options, callback*/) {
        if (this.socket) {
            this.socket.emit("/collection/add", ...arguments);
        }
    }

    /**
    * Runs a query on a collection

    * @param {String} name The collection"s name on which the query should be run, the default collection is used if undefined
    * @param {Object} query The options of the query to run
    * @param {Object}   query.where The query"s where clause  (see LokiJS:Resultset.find)
    * @param {Array}    query.sort Array of property names or subarray of [propertyname, isdesc] used to evaluate sort order, (see LokiJS:Resultset.compoundsort)
    * @param {Number}   query.limit Limit the number of returned items (see LokiJS:Resultset.limit)
    * @param {Number}   query.offset An offset to skip a number of items in the result (see LokiJS:Resultset.offset)
    * @param {Object}   query.count Executes the query as a count query, only returning the number of results (see LokiJS:Resultset.count)
    * @param {Function} callback The callback to invoke with the returned set
    */
    queryCollectionItems(/*name, query, callback*/) {
        if (this.socket) {
            this.socket.emit("/collection/items/query", ...arguments);
        }
    }

    /**
    * Updates a collection"s items based on a query

    * @param {String} name The collection"s name
    * @param {Object} data The data to update the items with
    * @param {Object} query The options of the query to run
    * @param {Object}   query.where The query"s where clause (see LokiJS:Resultset.find)
    * @param {Array}    query.sort Array of property names or subarray of [propertyname, isdesc] used to evaluate sort order, (see LokiJS:Resultset.compoundsort)
    * @param {Number}   query.limit Limit the number of returned items (see LokiJS:Resultset.limit)
    * @param {Number}   query.offset An offset to skip a number of items in the result (see LokiJS:Resultset.offset)
    * @param {Function} [callback] The callback to invoke with the count of updated items
    */
    updateCollectionItems(/*name, data, query, callback*/) {
        if (this.socket) {
            this.socket.emit("/collection/items/update", ...arguments);
        }
    }

    /**
    * Removes a collection"s items based on a query

    * @param {String} name The collection"s name
    * @param {Object} query The options of the query to run
    * @param {Object}   query.where The query"s where clause (see LokiJS:Resultset.find)
    * @param {Array}    query.sort Array of property names or subarray of [propertyname, isdesc] used to evaluate sort order, (see LokiJS:Resultset.compoundsort)
    * @param {Number}   query.limit Limit the number of returned items (see LokiJS:Resultset.limit)
    * @param {Number}   query.offset An offset to skip a number of items in the result (see LokiJS:Resultset.offset)
    * @param {Function} [callback] The callback to invoke with the count of removed items
    */
    removeCollectionItems(/*name, query, callback*/) {
        if (this.socket) {
            this.socket.emit("/collection/items/remove", ...arguments);
        }
    }

    /**
    * Clears a collection

    * @param {String} name The collection"s name
    * @param {Object} [options] Options to configure the clear behavior
    * @param {Boolean}  [options.removeIndices] Whether to also remove indices from the collection
    */
    clearCollection(/*name, options, callback*/) {
        if (this.socket) {
            this.socket.emit("/collection/clear", ...arguments);
        }
    }

    /**
    * Removes a collection
    * @param {String} name The collection"s name
    */
    removeCollection(/*name, callback*/) {
        if (this.socket) {
            this.socket.emit("/collection/remove", ...arguments);
        }
    }

    /**
    * Adds an item to a collection

    * @param {Object} data The data used to create the new item
    * @param {String} [collection] The collection"s name to which the item should belong, the default collection is used if undefined
    * @param {Function} [callback] The callback to invoke with the added item
    */
    addItem(data/*, collection*/, callback) {
        if (typeof data !== "object") {
            console.error("data needs to be an object");
            callback(null);
            return;
        }

        if (this.socket) {
            this.socket.emit("/item/add", ...arguments);
        }
    }

    /**
    * Get"s an item from a collection by it"s ID

    * @param {Number} id The item"s id
    * @param {String} [collection] The collection"s name to which the item belongs, the default collection is used if undefined
    * @param {Function} [callback] The callback to invoke with the item
    */
    getItem(/*id, collection, callback*/) {
        if (this.socket) {
            this.socket.emit("/item/get", ...arguments);
        }
    }

    /**
    * Get"s an item"s ID

    * @param {Object} item The item
    */
    getItemID(item) {
        if (item && item.$loki) {
            return item.$loki;
        }

        return null;
    }

    /**
    * Updates an item in a collection

    * @param {Number} id The item"s id
    * @param {Object} data The data to update the item with
    * @param {String} [collection] The collection"s name to which the item belongs, the default collection is used if undefined
    * @param {Function} [callback] The callback to invoke with the updated item
    */
    updateItem(/*id, data, collection, callback*/) {
        if (this.socket) {
            this.socket.emit("/item/update", ...arguments);
        }
    }

    /**
    * Removes an item from a collection

    * @param {Object} item The item to remove
    * @param {String} [collection] The collection"s name to which the item belongs, the default collection is used if undefined
    * @param {Function} [callback] The callback to invoke with the removed item
    */
    removeItem(/*id, collection, callback*/) {
        if (this.socket) {
            this.socket.emit("/item/remove", ...arguments);
        }
    }

    /**
    * Get the socket id
    */
    getID() {
        return this.id;
    }
}