Skip to content

Instantly share code, notes, and snippets.

@Joaquin6
Last active February 27, 2019 09:49
Show Gist options
  • Save Joaquin6/968748461e877569b0a659d9dcfd2d0e to your computer and use it in GitHub Desktop.
Save Joaquin6/968748461e877569b0a659d9dcfd2d0e to your computer and use it in GitHub Desktop.
a background script for chrome extensions to check internet connection
(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;
});
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();
});
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