Created
September 2, 2023 08:17
-
-
Save mdsohelmia/db5a512ade21259580eea2b3fa6d1750 to your computer and use it in GitHub Desktop.
rum.js
This file contains 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
"use strict"; | |
(function (window) { | |
// Insight API | |
var API_URL = 'https://rum-cdn.cdnmadeeasy.com'; | |
// Get resources list from the API | |
var RESOURCES_URL = 'https://rum-cdn.cdnmadeeasy.com/providers'; | |
// Resources list TTL in the LocalStorage(5 minutes) | |
var RESOURCES_TTL = 5 * 60 * 1000; // Resources list TTL in the LocalStorage(5 minutes) | |
var QUEUE_LIMIT = 10; // Defaults for repeats. Those could be overridden by settings from rum-cdn | |
var REPEAT_DELAY = 60 * 1000; // How often the script will measure CDN performance while user staying on the same page | |
var REPEAT_COUNT = 3; // How many times repeat | |
var _ref = function () { | |
/* minified */ | |
}.toString().indexOf('minified') !== -1 ? { | |
logInfo: console.log, | |
logError: console.error | |
} : { | |
logInfo: function logInfo() { }, | |
logError: function logError() { } | |
}, | |
logInfo = _ref.logInfo, | |
logError = _ref.logError; | |
// eslint-disable-next-line no-unused-vars | |
var customMeta = window.rum ? window.rum.customMeta : undefined; | |
var clientKey = window.rum ? window.rum.key : undefined; | |
var clientToken = window.rum ? window.rum.token : undefined; | |
function formatTiming(value) { | |
return Math.max(0, Number(value.toFixed(2))); | |
} | |
function fetch(url) { | |
var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, | |
_ref2$cb = _ref2.cb, | |
cb = _ref2$cb === void 0 ? function () { } : _ref2$cb, | |
data = _ref2.data, | |
_ref2$method = _ref2.method, | |
method = _ref2$method === void 0 ? 'GET' : _ref2$method, | |
_ref2$timeout = _ref2.timeout, | |
timeout = _ref2$timeout === void 0 ? 3000 : _ref2$timeout; | |
return new Promise(function (resolve, reject) { | |
var xhr = new XMLHttpRequest(); | |
xhr.onload = function () { | |
return resolve(xhr); | |
}; | |
xhr.ontimeout = function () { | |
reject('timeout'); | |
}; | |
xhr.onerror = function () { | |
var errorMsg = "Unknown error happen when fetching ".concat(url); | |
if (xhr.status !== 0) { | |
errorMsg = "Error happen when fetching ".concat(url, ". Status ").concat(xhr.status, ". Response: ").concat(xhr.statusText); | |
} | |
reject(new Error(errorMsg)); | |
}; | |
xhr.open(method, url); // needs to happen after .open() because IE | |
xhr.timeout = timeout; | |
cb(xhr); | |
xhr.send(data); | |
}); | |
} | |
function fetchJs(url, cb) { | |
var script = document.createElement('script'); | |
var loaded = false; | |
script.onreadystatechange = script.onload = function () { | |
if (!loaded) { | |
cb(); | |
} | |
loaded = true; | |
}; | |
script.setAttribute('src', url); | |
document.body.appendChild(script); | |
} | |
function fetchResource(resource) { | |
var url = "".concat(resource.cdnUrl, "?t=").concat(Date.now()); | |
var domain = new URL(url).hostname; | |
var result = { | |
id: resource.id, | |
domain: domain, | |
online: navigator && navigator.onLine !== undefined ? Number(navigator.onLine) : -1 | |
}; | |
return fetch(url).then(function (xhr) { | |
var timing = performance.getEntriesByName(url)[0]; | |
var dnsLookupTime = formatTiming(timing.domainLookupEnd - timing.domainLookupStart); | |
var tcpTime = formatTiming(timing.connectEnd - timing.connectStart); // In Firefox if connection was cached - secure connection time is calculated | |
// as a difference between the page is loaded and current request execution started | |
// which is equal to the time spent on the page. That's why we check if actual tcp connection time is calculated. | |
var sslTime = tcpTime > 0 ? formatTiming(timing.connectEnd - timing.secureConnectionStart) : 0; | |
if (xhr.status >= 200 && xhr.status < 300) { | |
// Add success response measurements | |
result = Object.assign({}, result, { | |
up: 1, | |
status: xhr.status, | |
time: Number((timing.responseEnd - timing.requestStart).toFixed(2)), | |
dnsLookupTime: dnsLookupTime, | |
tcpTime: tcpTime, | |
sslTime: sslTime, | |
headers: xhr.getAllResponseHeaders() | |
}); | |
} | |
if (xhr.status >= 300 && xhr.status <= 500) { | |
// HTTP Redirect/Error | |
result = Object.assign({}, result, { | |
up: 0, | |
status: xhr.status, | |
dnsLookupTime: dnsLookupTime, | |
tcpTime: tcpTime, | |
sslTime: sslTime, | |
headers: xhr.getAllResponseHeaders() | |
}); | |
} | |
return result; | |
}).catch(function () { | |
return Object.assign({}, result, { | |
up: 0, | |
status: 0 | |
}); | |
}); | |
} | |
function fetchResourceList() { | |
var key = 'gotipath-rum-resources'; | |
var resources = JSON.parse(window.localStorage.getItem(key)); | |
if (resources && resources.expiry > Date.now()) { | |
if (resources.config) setConfig(resources.config); | |
return Promise.resolve(resources.data); | |
} | |
return fetch(RESOURCES_URL).then(function (xhr) { | |
return JSON.parse(xhr.response); | |
}).then(function (response) { | |
if (!response || !response.data || !response.data.length) { | |
throw new Error('Empty response.data'); | |
} | |
// Store resources list in the LocalStorage | |
window.localStorage.setItem(key, JSON.stringify({ | |
data: response.data, | |
config: response.config, | |
expiry: Date.now() + RESOURCES_TTL | |
})); | |
if (response.config) setConfig(response.config); | |
return response.data; | |
}).catch(function () { | |
// eslint-disable-next-line | |
return [ | |
{ | |
"id": 1, | |
"cdnUrl": "https://rum-monitoring.gotipath.com/500b-bench.jpg", | |
"p": 1 | |
}, | |
{ | |
"id": 2, | |
"cdnUrl": "https://rum-monitoring.gcdn.co/500b-bench.jpg", | |
"p": 1 | |
} | |
]; | |
}); | |
} | |
function setConfig(config) { | |
REPEAT_DELAY = config.interval ? parseInt(config.interval) * 1000 : REPEAT_DELAY; | |
if (config.repeats) { | |
REPEAT_COUNT = config.repeats === 'Infinite' ? Math.pow(2, 32) // 4294967296 | |
: | |
parseInt(config.repeats); | |
} | |
} // eslint-disable-next-line no-unused-vars | |
function logSample(data) { | |
var oneIn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000; | |
data.clientVersion = '1'; | |
if (Math.random() < 1 / oneIn) { | |
fetch("".concat(API_URL, "/debug/log"), { | |
data: JSON.stringify(data), | |
method: 'POST' | |
}); | |
} | |
} | |
function pMapSeries(array, fn) { | |
return array.reduce(function (acc, value) { | |
return acc.then(function (array) { | |
return fn(value).then(function (result) { | |
return array.push(result), array; | |
}); | |
}); | |
}, Promise.resolve([])); | |
} | |
function isBatchSafe(batch) { | |
var tooSlow = 0; | |
var down = 0; // Calculate number of down and slow | |
batch.forEach(function (data) { | |
if (!data.up) { | |
down++; | |
} else if (data.time > 2000) { | |
tooSlow++; | |
} | |
}); // If all in batch down or slow then skip data | |
return down + tooSlow < batch.length; | |
} | |
function run() { | |
var numberOfRepeat = 0; | |
var processor = function processor() { | |
fetchResourceList().then(function (response) { | |
var metadata = { | |
ua: navigator.userAgent, | |
hostname: window.location.hostname, | |
client: clientKey | |
}; | |
var results = []; | |
performance.clearResourceTimings(); | |
var processBatch = function processBatch() { | |
var batch = results.splice(0, results.length); // If batch is safe to store do it, else just skip data | |
if (isBatchSafe(batch)) { | |
return storeResults(metadata, batch); | |
} | |
return batch; | |
}; | |
var processFetchResults = function processFetchResults(data) { | |
// Skip data if time not between 3 and 3000 ms | |
if (data.time < 3 || data.time > 3000) { | |
return false; | |
} | |
if (results.push(data) >= QUEUE_LIMIT) { | |
return processBatch(); | |
} | |
}; | |
return pMapSeries(response, function (resource) { | |
return fetchResource(resource).then(processFetchResults); | |
}).then(processBatch); | |
}).then(logInfo, logError).then(function () { | |
numberOfRepeat += 1; | |
if (numberOfRepeat < REPEAT_COUNT) { | |
setTimeout(processor, REPEAT_DELAY); | |
} | |
}); | |
}; // prettier-ignore | |
// eslint-disable-next-line comma-dangle | |
setTimeout(processor, 3000); | |
} | |
function storeResults(metadata, data) { | |
// @IDEA Remove return to make async data store and do not wait for it before making another test | |
return fetch("".concat(API_URL, "/rum/v1"), { | |
data: JSON.stringify({ | |
metadata: metadata, | |
data: data | |
}), | |
method: 'POST' | |
}).catch(logError); | |
} | |
function onLoad(fn) { | |
if (document.readyState === 'complete') { | |
fn(); | |
} else { | |
window.addEventListener('load', fn); | |
} | |
} | |
onLoad(function () { | |
var knownBots = ['bot', 'headless', 'google', 'baidu', 'bing', 'msn', 'duckduckbot', 'teoma', 'slurp', 'yandex', 'phantomjs', 'pingdom', 'ahrefsbot']; | |
var botString = knownBots.join('|'); | |
var botTestRegex = new RegExp(botString, 'i'); | |
console.log(botString); | |
var isProbablyBot = botTestRegex.test(window.navigator.userAgent); | |
console.log("isProbablyBot", isProbablyBot); | |
if (isProbablyBot) { | |
console.warn('PerfOps RUM not launching due to suspicious userAgent:', window.navigator.userAgent); | |
return; | |
} | |
if (typeof window.performance === 'undefined') { | |
return; | |
} // Clear performance API entries buffer when full | |
performance.onresourcetimingbufferfull = function () { | |
logInfo('clear performance resource buffer'); | |
performance.clearResourceTimings(); | |
}; | |
if (typeof Promise === 'function') { | |
return run(); | |
} | |
}); | |
})(window); | |
async function generateHMAC(sharedSecret, data) { | |
const encoder = new TextEncoder(); | |
const secretKeyBuffer = await crypto.subtle.importKey( | |
'raw', | |
encoder.encode(sharedSecret), | |
{ name: 'HMAC', hash: 'SHA-256' }, | |
false, | |
['sign'] | |
); | |
const dataBuffer = encoder.encode(data); | |
const hmacBuffer = await crypto.subtle.sign('HMAC', secretKeyBuffer, dataBuffer); | |
const hmacArray = Array.from(new Uint8Array(hmacBuffer)); | |
const hmacDigest = hmacArray.map(byte => byte.toString(16).padStart(2, '0')).join(''); | |
return hmacDigest; | |
} | |
var navigator_info = window.navigator; | |
console.log("navigator_info", navigator_info); | |
var screen_info = window.screen; | |
console.log("screen_info", screen_info); | |
var uid = navigator_info.mimeTypes.length; | |
uid += navigator_info.userAgent.replace(/\D+/g, ''); | |
uid += navigator_info.plugins.length; | |
uid += screen_info.height || ''; | |
uid += screen_info.width || ''; | |
uid += screen_info.pixelDepth || ''; | |
uid += navigator_info.hardwareConcurrency || ''; | |
console.log("hardwareConcurrency", navigator_info.hardwareConcurrency); | |
uid += navigator_info.productSub || ''; | |
uid += navigator_info.platform.length || ''; | |
console.log(uid); | |
document.write(uid); | |
console.log(window.navigator.userAgent); | |
// function generateFingerprint() { | |
// var fingerprint = ''; | |
// // User Agent | |
// fingerprint += navigator.userAgent; | |
// // Screen Resolution | |
// fingerprint += screen.width + 'x' + screen.height; | |
// // Installed Fonts | |
// var fonts = ''; | |
// for (var i = 0; i < navigator.fonts.length; i++) { | |
// fonts += navigator.fonts[i].family + ','; | |
// } | |
// fingerprint += fonts; | |
// // Time Zone Offset | |
// fingerprint += new Date().getTimezoneOffset(); | |
// // Other attributes you can include: language preferences, browser plugins, etc. | |
// return fingerprint; | |
// } | |
// // Example usage | |
// var fingerprint = generateFingerprint(); | |
// console.log(fingerprint); | |
var os = [ | |
{ name: 'Windows Phone', value: 'Windows Phone', version: 'OS' }, | |
{ name: 'Windows', value: 'Win', version: 'NT' }, | |
{ name: 'iPhone', value: 'iPhone', version: 'OS' }, | |
{ name: 'iPad', value: 'iPad', version: 'OS' }, | |
{ name: 'Kindle', value: 'Kindle', version: 'Silk' }, | |
{ name: 'Android', value: 'Android', version: 'Android' }, | |
{ name: 'BlackBerry', value: 'BlackBerry', version: '/' }, | |
{ name: 'Macintosh', value: 'Mac', version: 'OS X' }, | |
{ name: 'Linux', value: 'Linux', version: 'rv' }, | |
{ name: 'Palm', value: 'Palm', version: 'PalmOS' }, | |
{ name: 'Chrome OS', value: 'CrOS', version: 'CrOS' }, | |
{ name: 'FreeBSD', value: 'FreeBSD', version: 'FreeBSD' }, | |
{ name: 'OpenBSD', value: 'OpenBSD', version: 'OpenBSD' }, | |
{ name: 'Solaris', value: 'Solaris', version: 'SunOS' }, | |
{ name: 'IBM AIX', value: 'AIX', version: 'AIX' } | |
]; | |
var browser = [ | |
{ name: 'Google Chrome', value: 'Chrome', version: 'Chrome' }, | |
{ name: 'Mozilla Firefox', value: 'Firefox', version: 'Firefox' }, | |
{ name: 'Microsoft Edge', value: 'Edge', version: 'Edge' }, | |
{ name: 'Safari', value: 'Safari', version: 'Version' }, | |
{ name: 'Opera', value: 'Opera', version: 'Opera' }, | |
{ name: 'Internet Explorer', value: 'Internet Explorer', version: 'MSIE' }, | |
{ name: 'Brave', value: 'Brave', version: 'Brave' }, | |
{ name: 'Vivaldi', value: 'Vivaldi', version: 'Vivaldi' }, | |
{ name: 'UC Browser', value: 'UCBrowser', version: 'UCBrowser' }, | |
{ name: 'Samsung Internet', value: 'SamsungBrowser', version: 'SamsungBrowser' }, | |
{ name: 'Maxthon', value: 'Maxthon', version: 'Maxthon' }, | |
{ name: 'Yandex Browser', value: 'YaBrowser', version: 'YaBrowser' }, | |
{ name: 'Torch Browser', value: 'Torch', version: 'Torch' }, | |
{ name: 'Pale Moon', value: 'PaleMoon', version: 'PaleMoon' }, | |
{ name: 'SeaMonkey', value: 'SeaMonkey', version: 'SeaMonkey' } | |
]; | |
var header = [ | |
navigator.platform, | |
navigator.userAgent, | |
navigator.appVersion, | |
navigator.vendor, | |
window.opera | |
]; | |
function matchItem(string, data) { | |
var i = 0, | |
j = 0, | |
html = '', | |
regex, | |
regexv, | |
match, | |
matches, | |
version; | |
for (i = 0; i < data.length; i += 1) { | |
regex = new RegExp(data[i].value, 'i'); | |
match = regex.test(string); | |
if (match) { | |
regexv = new RegExp(data[i].version + '[- /:;]([\d._]+)', 'i'); | |
matches = string.match(regexv); | |
version = ''; | |
if (matches) { if (matches[1]) { matches = matches[1]; } } | |
if (matches) { | |
matches = matches.split(/[._]+/); | |
for (j = 0; j < matches.length; j += 1) { | |
if (j === 0) { | |
version += matches[j] + '.'; | |
} else { | |
version += matches[j]; | |
} | |
} | |
} else { | |
version = '0'; | |
} | |
return { | |
name: data[i].name, | |
version: parseFloat(version) | |
}; | |
} | |
} | |
return { name: 'unknown', version: 0 }; | |
} | |
var agent = header.join(' '); | |
var os = this.matchItem(agent, os); | |
var browser = this.matchItem(agent, browser); | |
// Device Information | |
var deviceType = navigator.userAgent.match(/Mobi/i) ? 'Mobile' : 'Desktop'; | |
var deviceBrand = navigator.vendor || 'Unknown'; | |
var deviceName = navigator.platform || 'Unknown'; | |
// Screen Information | |
var screenHeight = window.screen.height || 'Unknown'; | |
var screenWidth = window.screen.width || 'Unknown'; | |
var pixelDensity = window.devicePixelRatio || 'Unknown'; | |
// GPU Information | |
var gpu = navigator.userAgent.match(/AppleWebKit|Chrome|Gecko/i) ? 'GPU available' : 'GPU not available'; | |
// Browser Information | |
var browserName = navigator.userAgent.split(' ')[0]; | |
var browserVersion = navigator.userAgent.match(/(?:Version|Chrome|Firefox|MSIE|Edge)\/([\d.]+)/)[1] || 'Unknown'; | |
// OS Information | |
var osName = navigator.appVersion.match(/(Mac|Windows|Linux)/i)[0] || 'Unknown'; | |
var osCodeName = navigator.appVersion.match(/(NT|Intel|PPC|Mac)/i)[0] || 'Unknown'; | |
var osVersion = navigator.appVersion.match(/(NT|Intel|PPC|Mac).*?([\d._]+)/)[2] || 'Unknown'; | |
// Touchscreen Capabilities | |
var isTouchscreen = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment