Last active
March 4, 2018 20:15
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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