Skip to content

Instantly share code, notes, and snippets.

@lucabertolasi
Last active March 4, 2018 20:15
Show Gist options
  • Save lucabertolasi/66d7a39138a9b4bdcd4214a7e57b47e9 to your computer and use it in GitHub Desktop.
Save lucabertolasi/66d7a39138a9b4bdcd4214a7e57b47e9 to your computer and use it in GitHub Desktop.
[JavaScript] [AngularJS] [Cordova] [cordovaHTTP] cordovaHTTPool avoids multiple cordovaHTTP requests to conflict, since they cannot be cancelled.
/**
* @license
* Copyright (c) 2017-present, Luca Bertolasi. All Rights Reserved.
*
* This software is licensed under the terms of the MIT license,
* a copy of which can be found at https://opensource.org/licenses/MIT
*/
// REQUIRES: https://github.com/wymsee/cordova-HTTP
(() => {
/**
* cordovaHTTPool avoids multiple cordovaHTTP requests to conflict, since they cannot be cancelled.
*
* Because there is no way to cancel cordovaHTTP requests,
* we put all of them in a queue and execute them synchronously.
* When the app goes background,
* we either prevent any request from being made or
* execute the 'cancel' callback of the current request,
* eventually purging the queue.
*/
angular
.module('cordovaHTTPool', ['cordovaHTTP'])
.factory('cordovaHTTPool', cordovaHTTPool);
/* @ngInject */
function cordovaHTTPool(cordovaHTTP) {
const MODEL = {};
//removeIf(production)
window.model.cordovaHTTPool = MODEL;
//endRemoveIf(production)
MODEL.pendingRequests = [];
// cordova 'deviceready'
document.addEventListener('deviceready', e => {
document.addEventListener('resign', e => { isBackground(true) }, false) // background // iOS only
document.addEventListener('pause' , e => { isBackground(true) }, false) // background // iOS & Android
document.addEventListener('resume', e => { isBackground(false) }, false) // foreground // iOS & Android
document.addEventListener('active', e => { isBackground(false) }, false) // foreground // iOS only
}, false);
// USAGE
//
// cordovaHTTPool.enqueue([{
// method,
// endpoint,
// params,
// headers,
// callback: {
// data,
// error,
// cancel
// }
// },{
// ... // we can enqueue multiple objects
// }])
//
// END
return {
enqueue,
execute,
isBackground,
isExecuting,
pendingRequests,
purge,
responseCallback,
shouldCancel
}
function enqueue(objArr) {
pendingRequests(objArr)
isExecuting() ? null : execute()
} // enqueue
function execute() {
isExecuting(true)
const configObj = pendingRequests().shift() // removes the first element from an array and returns that element
if (configObj === undefined) {
//removeIf(production)
console.log(`---- cordovaHTTPool.factory -> execute : empty 'pendingRequests' -> stopping execution`);
//endRemoveIf(production)
isExecuting(false);
return;
} else if (angular.isArray(configObj)
|| !angular.isObject(configObj)
|| !angular.isString(configObj.endpoint)
|| configObj.endpoint.length === 0
|| !configObj.hasOwnProperty('callback')) {
//removeIf(production)
console.log(`---- cordovaHTTPool.factory -> execute : invalid 'configObj' -> executing next one`);
//endRemoveIf(production)
execute();
return
}
if (shouldCancel('execute', configObj)) { return }
//removeIf(production)
console.log(`---- cordovaHTTPool.factory -> execute : ${configObj.endpoint}`);
//endRemoveIf(production)
// window.fabric.Crashlytics.addLog(`---- cordovaHTTPool.factory -> execute : ${configObj.endpoint}`);
cordovaHTTP[configObj.method.toLowerCase()](
configObj.endpoint,
configObj.params || {},
configObj.headers || {})
// success
.then(response => {
responseCallback(configObj, response)
// error
}, response => {
responseCallback(configObj, response)
});
} // execute
function isBackground(bool) {
return typeof bool === "boolean" || bool === null
? MODEL.isBackground = bool
: MODEL.isBackground;
} // isBackground
function isExecuting(bool) {
return typeof bool === "boolean" || bool === null
? MODEL.isExecuting = bool
: MODEL.isExecuting
} // isExecuting
function pendingRequests(objArr) {
!!MODEL.pendingRequests
? null
: MODEL.pendingRequests = []
return angular.isArray(objArr)
? MODEL.pendingRequests.push(...objArr)
: MODEL.pendingRequests
} // pendingRequests
function purge() {
//removeIf(production)
console.log(`---- cordovaHTTPool.factory -> purge : emptying 'pendingRequests'`);
//endRemoveIf(production)
// https://stackoverflow.com/questions/1232040/how-do-i-empty-an-array-in-javascript
pendingRequests().length = 0;
isExecuting(false);
} // purge
function responseCallback(configObj, response){
// configObj = { ..., callback: { data, error, cancel }}
// response : data = { data, status, header }
// response : error = { error, status, header }
if (shouldCancel('responseCallback', configObj)) { return }
const RESPONSE_STATE = ['data', 'error'];
for (let i = 0; i < RESPONSE_STATE.length; i += 1) {
const state = RESPONSE_STATE[i]
if (response.hasOwnProperty(state)
&& configObj.callback.hasOwnProperty(state)) {
try {
response[state] = JSON.parse(response[state])
} catch (e) {
// do nothing, it's a string string not a JSON string
}
//removeIf(production)
console.log(`---- cordovaHTTPool.factory -> responseCallback -> ${state}`, response);
//endRemoveIf(production)
// window.fabric.Crashlytics.addLog(`---- cordovaHTTPool.factory -> responseCallback -> ${state}`); // privacy: do not log 'response'
configObj.callback[state](response)
break
}
}
execute()
} // responseCallback
function shouldCancel(pointOfExecution, configObj) {
if (isBackground()) {
//removeIf(production)
console.log(`---- cordovaHTTPool.factory -> ${pointOfExecution} -> isBackground`);
//endRemoveIf(production)
const state = 'cancel';
if (configObj.callback.hasOwnProperty(state)) { configObj.callback[state]() }
purge();
return true
}
return false
} // shouldCancel
} // cordovaHTTPool
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment