Last active
February 27, 2019 09:49
-
-
Save Joaquin6/968748461e877569b0a659d9dcfd2d0e to your computer and use it in GitHub Desktop.
a background script for chrome extensions to check internet connection
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
(function(global, conn) { | |
"use strict"; | |
if (global.document) { | |
conn(global) | |
} else { | |
return; | |
} | |
})(typeof window !== "undefined" ? window : this, function(window, noGlobal) { | |
var document = window.document; | |
var version = "1.0.0", | |
ConnectJS = function() { | |
console.log("ConnectJS Initialized") | |
}; | |
ConnectJS.fn = ConnectJS.prototype = { | |
connectjs: version | |
} | |
ConnectJS.extend = ConnectJS.fn.extend = function(){ | |
var name; | |
var target = arguments[0]; | |
ConnectJS = target; | |
return ConnectJS; | |
} | |
ConnectJS.extend({ | |
connected:function(callback){ | |
window.addEventListener('online',callback); | |
}, | |
disconnected:function(callback){ | |
window.addEventListener('offline',callback); | |
}, | |
statusChange:function(obj){ | |
window.addEventListener('online',obj.onConnect); | |
window.addEventListener('offline',obj.onDisconnect); | |
}, | |
isConnected:function(){ | |
return navigator.onLine; | |
} | |
}); | |
var _ConnectJS = window.ConnectJS, | |
_$$ = window.$$; | |
ConnectJS.noConflict = function() { | |
if (window.$$ === jQuery) { | |
window.$$ = _$$; | |
} | |
if (window.jQuery === jQuery) { | |
window.ConnectJS = _ConnectJS; | |
} | |
return ConnectJS; | |
}; | |
if (!noGlobal) { | |
window.ConnectJS = window.$$ = ConnectJS; | |
} | |
return ConnectJS; | |
}); |
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
const { API_BASE = 'http://www.google.com', NETWORK_CHECK_INTERVAL = 20 } = process.env; | |
class OptionsService { | |
save_options(options, callback) { | |
chrome.storage.sync.set(options, callback); | |
} | |
restore_options(callback) { | |
chrome.storage.sync.get({ | |
nbSamples: 5, | |
timeout: 4000, | |
url: API_BASE, | |
interval: NETWORK_CHECK_INTERVAL * 1000, | |
}, callback); | |
} | |
} | |
let options; | |
let interval; | |
let currentState = 'UNKNOWN'; | |
const stateHistory = []; | |
const maxLengthHistory = 30; | |
const bgLogId = 'Background Network [Log]:'; | |
const optionsService = new OptionsService(); | |
function handleChangeUrl() {} | |
function handleChangeInterval() {} | |
function handleChangeNbSamples() {} | |
function scheduleBackgroundTasks() { | |
if (interval) { | |
clearInterval(interval); | |
} | |
interval = setInterval(() => { | |
const samplePromises = []; | |
for (let i = 0; i < options.nbSamples; i++) { | |
samplePromises.push(isNetworkWorking()); | |
} | |
Promise.all(samplePromises) | |
.then(results => { | |
const stats = { | |
time: String(new Date()), | |
upCount: results.filter(r => r === true).length, | |
downCount: results.filter(r => r === false).length, | |
}; | |
// eslint-disable-next-line no-console | |
console.log(bgLogId, 'Stats:', JSON.stringify(stats)); | |
const working = stats.upCount > stats.downCount; | |
if (working) { | |
console.log(bgLogId, 'Network is up!'); // eslint-disable-line no-console | |
setNetworkUp(); | |
} else { | |
console.log(bgLogId, 'Network is down!'); // eslint-disable-line no-console | |
setNetworkDown(); | |
} | |
stateHistory.push(stats); | |
if (stateHistory.length > maxLengthHistory) { | |
stateHistory.splice(0, stateHistory.length - maxLengthHistory); | |
} | |
notifyState(stateHistory); | |
}); | |
}, options.interval); | |
} | |
export function dispatch(setting, change) { | |
const handlers = { | |
url: handleChangeUrl, | |
timeout: handleChangeTimeout, | |
interval: handleChangeInterval, | |
nbSamples: handleChangeNbSamples, | |
}; | |
const handler = handlers[setting]; | |
if (!handler) { | |
// eslint-disable-next-line no-console | |
console.log(bgLogId, 'No handler found for setting =>', setting); | |
} | |
options[setting] = change.newValue; | |
handler(setting, change); | |
} | |
export const getNetworkState = () => currentState; | |
function handleChangeTimeout() { | |
scheduleBackgroundTasks(); | |
} | |
function setNetworkUp() { | |
if (currentState !== 'UP') { | |
currentState = 'UP'; | |
} | |
} | |
function setNetworkDown() { | |
if (currentState !== 'DOWN') { | |
currentState = 'DOWN'; | |
} | |
} | |
function isNetworkWorking() { | |
const p = new Promise(resolve => { | |
const req = new XMLHttpRequest(); | |
req.onreadystatechange = function() { | |
if (this.readyState === XMLHttpRequest.DONE) { | |
resolve(this.status === 200); | |
} | |
}; | |
req.timeout = options.timeout; | |
req.open('GET', options.url + ((/\?/).test(options.url) ? '&' : '?') + (new Date()) | |
.getTime(), true); | |
return req.send(null); | |
}); | |
return p; | |
} | |
function notifyState(stateHistory) { | |
// eslint-disable-next-line no-console | |
console.log(bgLogId, 'Sending: ', JSON.stringify(stateHistory)); | |
chrome.runtime.sendMessage('notifying.state', { history: stateHistory }); | |
} | |
optionsService.restore_options(restoredOptions => { | |
options = restoredOptions; | |
console.log(bgLogId, 'Restored:', options); // eslint-disable-line no-console | |
scheduleBackgroundTasks(); | |
}); |
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
function getterSetter(variableParent, variableName, getterFunction, setterFunction) { | |
if (Object.defineProperty) { | |
Object.defineProperty(variableParent, variableName, { | |
get: getterFunction, | |
set: setterFunction | |
}); | |
} | |
else if (document.__defineGetter__) { | |
variableParent.__defineGetter__(variableName, getterFunction); | |
variableParent.__defineSetter__(variableName, setterFunction); | |
} | |
} | |
(function (w) { | |
w.onlinejs = w.onlinejs || {}; | |
//Checks interval can be changed in runtime | |
w.onLineCheckTimeout = 5000; | |
//Use window.onLineURL incapsulated variable | |
w.onlinejs._onLineURL = "http://offlinejs.com/online.php"; | |
w.onlinejs.setOnLineURL = function (newURL) { | |
w.onlinejs._onLineURL = newURL; | |
w.onlinejs.getStatusFromNavigatorOnLine(); | |
} | |
w.onlinejs.getOnLineURL = function () { | |
return w.onlinejs._onLineURL; | |
} | |
getterSetter(w, 'onLineURL', w.onlinejs.getOnLineURL, w.onlinejs.setOnLineURL); | |
//Verification logic | |
w.onlinejs.setStatus = function (newStatus) { | |
w.onlinejs.fireHandlerDependOnStatus(newStatus); | |
w.onLine = newStatus; | |
} | |
w.onlinejs.fireHandlerDependOnStatus = function (newStatus) { | |
if (newStatus === true && w.onLineHandler !== undefined && (w.onLine !== true || w.onlinejs.handlerFired === false)) { | |
w.onLineHandler(); | |
} | |
if (newStatus === false && w.offLineHandler !== undefined && (w.onLine !== false || w.onlinejs.handlerFired === false)) { | |
w.offLineHandler(); | |
} | |
w.onlinejs.handlerFired = true; | |
}; | |
w.onlinejs.startCheck = function () { | |
setInterval("window.onlinejs.logic.checkConnectionWithRequest(true)", w.onLineCheckTimeout); | |
} | |
w.onlinejs.stopCheck = function () { | |
clearInterval("window.onlinejs.logic.checkConnectionWithRequest(true)", w.onLineCheckTimeout); | |
} | |
w.checkOnLine = function () { | |
w.onlinejs.logic.checkConnectionWithRequest(false); | |
} | |
w.onlinejs.getOnLineCheckURL = function () { | |
return w.onlinejs._onLineURL + '?' + Math.floor(Math.random() * 1000000); | |
} | |
w.onlinejs.getStatusFromNavigatorOnLine = function () { | |
if (w.navigator.onLine !== undefined) { | |
w.onlinejs.setStatus(w.navigator.onLine); | |
} else { | |
w.onlinejs.setStatus(true); | |
} | |
} | |
//Network transport layer | |
var xmlhttp = new XMLHttpRequest(); | |
w.onlinejs.isXMLHttp = function () { | |
return "withCredentials" in xmlhttp; | |
} | |
w.onlinejs.isXDomain = function () { | |
return typeof XDomainRequest != "undefined"; | |
} | |
//For IE we use XDomainRequest and sometimes it uses a bit different logic, so adding decorator for this | |
w.onlinejs.XDomainLogic = { | |
init: function () { | |
xmlhttp = new XDomainRequest(); | |
xmlhttp.onerror = function () { | |
xmlhttp.status = 404; | |
w.onlinejs.processXmlhttpStatus(); | |
} | |
xmlhttp.ontimeout = function () { | |
xmlhttp.status = 404; | |
w.onlinejs.processXmlhttpStatus(); | |
} | |
}, | |
onInternetAsyncStatus: function () { | |
try { | |
xmlhttp.status = 200; | |
w.onlinejs.processXmlhttpStatus(); | |
} catch (err) { | |
w.onlinejs.setStatus(false); | |
} | |
}, | |
checkConnectionWithRequest: function (async) { | |
xmlhttp.onload = w.onlinejs.logic.onInternetAsyncStatus; | |
var url = w.onlinejs.getOnLineCheckURL(); | |
xmlhttp.open("GET", url); | |
w.onlinejs.tryToSend(xmlhttp); | |
} | |
} | |
//Another case for decoration is XMLHttpRequest | |
w.onlinejs.XMLHttpLogic = { | |
init: function () { | |
}, | |
onInternetAsyncStatus: function () { | |
if (xmlhttp.readyState === 4) { | |
try { | |
w.onlinejs.processXmlhttpStatus(); | |
} catch (err) { | |
w.onlinejs.setStatus(false); | |
} | |
} | |
}, | |
checkConnectionWithRequest: function (async) { | |
if (async) { | |
xmlhttp.onreadystatechange = w.onlinejs.logic.onInternetAsyncStatus; | |
} else { | |
xmlhttp.onreadystatechange = undefined; | |
} | |
var url = w.onlinejs.getOnLineCheckURL(); | |
xmlhttp.open("HEAD", url, async); | |
w.onlinejs.tryToSend(xmlhttp); | |
if (async === false) { | |
w.onlinejs.processXmlhttpStatus(); | |
return w.onLine; | |
} | |
} | |
} | |
if (w.onlinejs.isXDomain()) { | |
w.onlinejs.logic = w.onlinejs.XDomainLogic; | |
} else { | |
w.onlinejs.logic = w.onlinejs.XMLHttpLogic; | |
} | |
w.onlinejs.processXmlhttpStatus = function () { | |
var tempOnLine = w.onlinejs.verifyStatus(xmlhttp.status); | |
w.onlinejs.setStatus(tempOnLine); | |
} | |
w.onlinejs.verifyStatus = function (status) { | |
return status === 200; | |
} | |
w.onlinejs.tryToSend = function (xmlhttprequest) { | |
try { | |
xmlhttprequest.send(); | |
} catch(e) { | |
w.onlinejs.setStatus(false); | |
} | |
} | |
//Events handling | |
w.onlinejs.addEvent = function (obj, type, callback) { | |
if (window.attachEvent) { | |
obj.attachEvent('on' + type, callback); | |
} else { | |
obj.addEventListener(type, callback); | |
} | |
} | |
w.onlinejs.addEvent(w, 'load', function () { | |
w.onlinejs.fireHandlerDependOnStatus(w.onLine); | |
}); | |
w.onlinejs.addEvent(w, 'online', function () { | |
window.onlinejs.logic.checkConnectionWithRequest(true); | |
}) | |
w.onlinejs.addEvent(w, 'offline', function () { | |
window.onlinejs.logic.checkConnectionWithRequest(true); | |
}) | |
w.onlinejs.getStatusFromNavigatorOnLine(); | |
w.onlinejs.logic.init(); | |
w.checkOnLine(); | |
w.onlinejs.startCheck(); | |
w.onlinejs.handlerFired = false; | |
})(window); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment