123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- "use strict";
- var _CoreManager = _interopRequireDefault(require("./CoreManager"));
- var _ParseObject = _interopRequireDefault(require("./ParseObject"));
- var _ParseQuery = _interopRequireDefault(require("./ParseQuery"));
- var _Storage = _interopRequireDefault(require("./Storage"));
- function _interopRequireDefault(obj) {
- return obj && obj.__esModule ? obj : {
- default: obj
- };
- }
- /**
- * https://github.com/francimedia/parse-js-local-storage
- *
- * @flow
- */
- /*:: import type { SaveOptions } from './ParseObject';*/
- /*:: import type { RequestOptions } from './RESTController';*/
- /*:: type QueueObject = {
- queueId: string,
- action: string,
- object: ParseObject,
- serverOptions: SaveOptions | RequestOptions,
- id: string,
- className: string,
- hash: string,
- createdAt: Date,
- };*/
- /*:: type Queue = Array<QueueObject>;*/
- const QUEUE_KEY = 'Parse/Eventually/Queue';
- let queueCache = [];
- let dirtyCache = true;
- let polling = undefined;
- /**
- * Provides utility functions to queue objects that will be
- * saved to the server at a later date.
- *
- * @class Parse.EventuallyQueue
- * @static
- */
- const EventuallyQueue = {
- /**
- * Add object to queue with save operation.
- *
- * @function save
- * @name Parse.EventuallyQueue.save
- * @param {ParseObject} object Parse.Object to be saved eventually
- * @param {object} [serverOptions] See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Object.html#save Parse.Object.save} options.
- * @returns {Promise} A promise that is fulfilled if object is added to queue.
- * @static
- * @see Parse.Object#saveEventually
- */
- save(object /*: ParseObject*/, serverOptions /*: SaveOptions*/ = {}) /*: Promise*/{
- return this.enqueue('save', object, serverOptions);
- },
- /**
- * Add object to queue with save operation.
- *
- * @function destroy
- * @name Parse.EventuallyQueue.destroy
- * @param {ParseObject} object Parse.Object to be destroyed eventually
- * @param {object} [serverOptions] See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Object.html#destroy Parse.Object.destroy} options
- * @returns {Promise} A promise that is fulfilled if object is added to queue.
- * @static
- * @see Parse.Object#destroyEventually
- */
- destroy(object /*: ParseObject*/, serverOptions /*: RequestOptions*/ = {}) /*: Promise*/{
- return this.enqueue('destroy', object, serverOptions);
- },
- /**
- * Generate unique identifier to avoid duplicates and maintain previous state.
- *
- * @param {string} action save / destroy
- * @param {object} object Parse.Object to be queued
- * @returns {string}
- * @static
- * @ignore
- */
- generateQueueId(action /*: string*/, object /*: ParseObject*/) /*: string*/{
- object._getId();
- const {
- className,
- id,
- _localId
- } = object;
- const uniqueId = object.get('hash') || _localId;
- return [action, className, id, uniqueId].join('_');
- },
- /**
- * Build queue object and add to queue.
- *
- * @param {string} action save / destroy
- * @param {object} object Parse.Object to be queued
- * @param {object} [serverOptions]
- * @returns {Promise} A promise that is fulfilled if object is added to queue.
- * @static
- * @ignore
- */
- async enqueue(action /*: string*/, object /*: ParseObject*/, serverOptions /*: SaveOptions | RequestOptions*/) /*: Promise*/{
- const queueData = await this.getQueue();
- const queueId = this.generateQueueId(action, object);
- let index = this.queueItemExists(queueData, queueId);
- if (index > -1) {
- // Add cached values to new object if they don't exist
- for (const prop in queueData[index].object) {
- if (typeof object.get(prop) === 'undefined') {
- object.set(prop, queueData[index].object[prop]);
- }
- }
- } else {
- index = queueData.length;
- }
- queueData[index] = {
- queueId,
- action,
- object: object.toJSON(),
- serverOptions,
- id: object.id,
- className: object.className,
- hash: object.get('hash'),
- createdAt: new Date()
- };
- return this.setQueue(queueData);
- },
- store(data) {
- return _Storage.default.setItemAsync(QUEUE_KEY, JSON.stringify(data));
- },
- load() {
- return _Storage.default.getItemAsync(QUEUE_KEY);
- },
- /**
- * Sets the in-memory queue from local storage and returns.
- *
- * @function getQueue
- * @name Parse.EventuallyQueue.getQueue
- * @returns {Promise<Array>}
- * @static
- */
- async getQueue() /*: Promise<Array>*/{
- if (dirtyCache) {
- queueCache = JSON.parse((await this.load()) || '[]');
- dirtyCache = false;
- }
- return queueCache;
- },
- /**
- * Saves the queue to local storage
- *
- * @param {Queue} queue Queue containing Parse.Object data.
- * @returns {Promise} A promise that is fulfilled when queue is stored.
- * @static
- * @ignore
- */
- setQueue(queue /*: Queue*/) /*: Promise<void>*/{
- queueCache = queue;
- return this.store(queueCache);
- },
- /**
- * Removes Parse.Object data from queue.
- *
- * @param {string} queueId Unique identifier for Parse.Object data.
- * @returns {Promise} A promise that is fulfilled when queue is stored.
- * @static
- * @ignore
- */
- async remove(queueId /*: string*/) /*: Promise<void>*/{
- const queueData = await this.getQueue();
- const index = this.queueItemExists(queueData, queueId);
- if (index > -1) {
- queueData.splice(index, 1);
- await this.setQueue(queueData);
- }
- },
- /**
- * Removes all objects from queue.
- *
- * @function clear
- * @name Parse.EventuallyQueue.clear
- * @returns {Promise} A promise that is fulfilled when queue is cleared.
- * @static
- */
- clear() /*: Promise*/{
- queueCache = [];
- return this.store([]);
- },
- /**
- * Return the index of a queueId in the queue. Returns -1 if not found.
- *
- * @param {Queue} queue Queue containing Parse.Object data.
- * @param {string} queueId Unique identifier for Parse.Object data.
- * @returns {number}
- * @static
- * @ignore
- */
- queueItemExists(queue /*: Queue*/, queueId /*: string*/) /*: number*/{
- return queue.findIndex(data => data.queueId === queueId);
- },
- /**
- * Return the number of objects in the queue.
- *
- * @function length
- * @name Parse.EventuallyQueue.length
- * @returns {number}
- * @static
- */
- async length() /*: number*/{
- const queueData = await this.getQueue();
- return queueData.length;
- },
- /**
- * Sends the queue to the server.
- *
- * @function sendQueue
- * @name Parse.EventuallyQueue.sendQueue
- * @returns {Promise<boolean>} Returns true if queue was sent successfully.
- * @static
- */
- async sendQueue() /*: Promise<boolean>*/{
- const queue = await this.getQueue();
- const queueData = [...queue];
- if (queueData.length === 0) {
- return false;
- }
- for (let i = 0; i < queueData.length; i += 1) {
- const queueObject = queueData[i];
- const {
- id,
- hash,
- className
- } = queueObject;
- const ObjectType = _ParseObject.default.extend(className);
- if (id) {
- await this.process.byId(ObjectType, queueObject);
- } else if (hash) {
- await this.process.byHash(ObjectType, queueObject);
- } else {
- await this.process.create(ObjectType, queueObject);
- }
- }
- return true;
- },
- /**
- * Build queue object and add to queue.
- *
- * @param {ParseObject} object Parse.Object to be processed
- * @param {QueueObject} queueObject Parse.Object data from the queue
- * @returns {Promise} A promise that is fulfilled when operation is performed.
- * @static
- * @ignore
- */
- async sendQueueCallback(object /*: ParseObject*/, queueObject /*: QueueObject*/) /*: Promise<void>*/{
- if (!object) {
- return this.remove(queueObject.queueId);
- }
- switch (queueObject.action) {
- case 'save':
- // Queued update was overwritten by other request. Do not save
- if (typeof object.updatedAt !== 'undefined' && object.updatedAt > new Date(queueObject.object.createdAt)) {
- return this.remove(queueObject.queueId);
- }
- try {
- await object.save(queueObject.object, queueObject.serverOptions);
- await this.remove(queueObject.queueId);
- } catch (e) {
- if (e.message !== 'XMLHttpRequest failed: "Unable to connect to the Parse API"') {
- await this.remove(queueObject.queueId);
- }
- }
- break;
- case 'destroy':
- try {
- await object.destroy(queueObject.serverOptions);
- await this.remove(queueObject.queueId);
- } catch (e) {
- if (e.message !== 'XMLHttpRequest failed: "Unable to connect to the Parse API"') {
- await this.remove(queueObject.queueId);
- }
- }
- break;
- }
- },
- /**
- * Start polling server for network connection.
- * Will send queue if connection is established.
- *
- * @function poll
- * @name Parse.EventuallyQueue.poll
- * @param [ms] Milliseconds to ping the server. Default 2000ms
- * @static
- */
- poll(ms /*: number*/ = 2000) {
- if (polling) {
- return;
- }
- polling = setInterval(() => {
- const RESTController = _CoreManager.default.getRESTController();
- RESTController.request('GET', 'health').then(({
- status
- }) => {
- if (status === 'ok') {
- this.stopPoll();
- return this.sendQueue();
- }
- }).catch(e => e);
- }, ms);
- },
- /**
- * Turns off polling.
- *
- * @function stopPoll
- * @name Parse.EventuallyQueue.stopPoll
- * @static
- */
- stopPoll() {
- clearInterval(polling);
- polling = undefined;
- },
- /**
- * Return true if pinging the server.
- *
- * @function isPolling
- * @name Parse.EventuallyQueue.isPolling
- * @returns {boolean}
- * @static
- */
- isPolling() /*: boolean*/{
- return !!polling;
- },
- _setPolling(flag /*: boolean*/) {
- polling = flag;
- },
- process: {
- create(ObjectType, queueObject) {
- const object = new ObjectType();
- return EventuallyQueue.sendQueueCallback(object, queueObject);
- },
- async byId(ObjectType, queueObject) {
- const {
- sessionToken
- } = queueObject.serverOptions;
- const query = new _ParseQuery.default(ObjectType);
- query.equalTo('objectId', queueObject.id);
- const results = await query.find({
- sessionToken
- });
- return EventuallyQueue.sendQueueCallback(results[0], queueObject);
- },
- async byHash(ObjectType, queueObject) {
- const {
- sessionToken
- } = queueObject.serverOptions;
- const query = new _ParseQuery.default(ObjectType);
- query.equalTo('hash', queueObject.hash);
- const results = await query.find({
- sessionToken
- });
- if (results.length > 0) {
- return EventuallyQueue.sendQueueCallback(results[0], queueObject);
- }
- return EventuallyQueue.process.create(ObjectType, queueObject);
- }
- }
- };
- module.exports = EventuallyQueue;
|