bbpro
Version:
BrowserBox - remote browser isolation tool
131 lines (111 loc) • 3.5 kB
JavaScript
import {CONFIG} from './common.js';
const StatusSymbol = Symbol(`[[ConnectivityStatus]]`);
export default class InternetChecker {
constructor(timeout = (CONFIG.privateConnectivity ? 6000 : 3700), debug = false) {
this.biasToVerification = CONFIG.privateConnectivity ? 0.618 : 0.8;
this.timeout = timeout;
this.debug = debug;
this.checkInProgress = false;
this[StatusSymbol] = 'issue';
this.urls = CONFIG.privateConnectivity ? [
location.origin,
location.origin
] : [
"https://1.1.1.1",
"https://dns.google",
"https://www.akamai.com",
"https://www.lumen.com",
"https://www.equinix.com",
"https://www.f5.com",
"https://www.cogentco.com",
"https://www.he.net",
"https://www.arista.com",
];
}
async singleCheck(url) {
const swatch = Math.random();
if ( swatch < this.biasToVerification ) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error("Request timed out")), this.timeout);
});
const fetchPromise = fetch(url, {
method: 'GET',
mode: 'no-cors'
});
return Promise.race([fetchPromise, timeoutPromise]);
} else if ( navigator.onLine ) {
return true;
} else {
throw new Error(`Offline`);
}
}
async checkInternet() {
if (this.checkInProgress) {
this.debug && console.log("Check already in progress, please wait.");
return { status: "in-progress" };
}
this.checkInProgress = true;
let status = 'issue';
let error;
if ( CONFIG.privateConnectivity ) {
try {
await this.singleCheck(this.urls[0]);
this.checkInProgress = false;
status = 'online'
} catch(e) {
this.checkInProgress = false;
this.status = 'offline';
}
this.status = status;
return { status };
} else {
// Shuffle and select two URLs
const shuffledUrls = this.urls.sort(() => 0.5 - Math.random());
const selectedUrls = shuffledUrls.slice(0, 2);
// Execute checks
try {
const results = await Promise.allSettled([
this.singleCheck(selectedUrls[0]),
this.singleCheck(selectedUrls[1])
]);
const successfulChecks = results.filter(r => r.status === 'fulfilled').length;
if (successfulChecks === 2) {
status = "online";
this.debug && console.log("You are online!");
} else if (successfulChecks === 0) {
status = "offline";
this.debug && console.log("You are offline!");
} else {
this.debug && console.log("Connection status is ambiguous. You might be experiencing network issues.");
status = 'issue';
}
this.checkInProgress = false;
} catch (err) {
this.checkInProgress = false;
this.debug && console.log("An error occurred while checking the connection.", err);
error = err;
this.status = 'error';
return { status: "error", error };
}
}
this.status = status;
return { status, error };
}
get status() {
return this[StatusSymbol];
}
set status(value) {
switch(value) {
case "online":
case "offline":
case "issue":
case "error":
this[StatusSymbol] = value;
break;
default: {
throw new TypeError(`Invalid value ${value} for Connectivity status enum`);
break;
}
}
}
}