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;
}
}