Skip to content
This repository has been archived by the owner on Nov 15, 2017. It is now read-only.

Commit

Permalink
refactoring, #24, #25, performance, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
gorhill committed Oct 23, 2013
1 parent 0c4d606 commit 59ef914
Show file tree
Hide file tree
Showing 11 changed files with 646 additions and 356 deletions.
173 changes: 111 additions & 62 deletions js/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,86 +21,145 @@

/******************************************************************************/

function asyncJobEntry(name) {
this.name = name;
this.data = null;
this.callback = null;
this.when = 0;
this.period = 0;
}

asyncJobEntry.prototype._nullify = function() {
this.data = null;
this.callback = null;
}

var asyncJobQueue = {
jobs: {},
jobCount: 0,
junkyard: [],
resolution: 200,

add: function(name, data, callback, delay, recurrent) {
var job = this.jobs[name];
if ( !job ) {
job = this.junkyard.pop();
if ( !job ) {
job = new asyncJobEntry(name);
} else {
job.name = name;
}
this.jobs[name] = job;
this.jobCount++;
}
job.data = data;
job.callback = callback;
job.when = Date.now() + delay;
job.period = recurrent ? delay : 0;
},

_process: function() {
var now = Date.now();
var keys = Object.keys(this.jobs);
var i = keys.length;
var job;
while ( i-- ) {
job = this.jobs[keys[i]];
if ( job.when > now ) {
continue;
}
job.callback(job.data);
if ( job.period ) {
job.when = now + job.period;
} else {
job._nullify();
delete this.jobs[job.name];
this.jobCount--;
this.junkyard.push(job);
}
}
}
};

function asyncJobQueueHandler() {
if ( asyncJobQueue.jobCount ) {
asyncJobQueue._process();
}
}

setInterval(asyncJobQueueHandler, 100);

/******************************************************************************/

// Update visual of extension icon.
// A time out is used to coalesce adjacents requests to update badge.

var updateBadgeTimers = {};

function updateBadge(pageUrl) {
if ( updateBadgeTimers[pageUrl] ) {
clearTimeout(updateBadgeTimers[pageUrl]);
asyncJobQueue.add('updateBadge ' + pageUrl, pageUrl, updateBadgeCallback, 250);
}

function updateBadgeCallback(pageUrl) {
if ( pageUrl === HTTPSB.behindTheSceneURL ) {
return;
}
var tabId = tabIdFromPageUrl(pageUrl);
if ( !tabId ) {
return;
}
updateBadgeTimers[pageUrl] = setTimeout(function() {
delete updateBadgeTimers[pageUrl];
var tabId = tabIdFromPageUrl(pageUrl);
if ( !tabId || tabId === HTTPSB.behindTheSceneTabId ) {
return;
var pageStats = pageStatsFromTabId(tabId);
var count = pageStats ? Object.keys(pageStats.requests).length : 0;
var countStr = count.toString();
if ( count >= 1000 ) {
if ( count < 10000 ) {
countStr = countStr.slice(0,1) + '.' + countStr.slice(1,-2) + 'K';
} else if ( count < 1000000 ) {
countStr = countStr.slice(0,-3) + 'K';
} else if ( count < 10000000 ) {
countStr = countStr.slice(0,1) + '.' + countStr.slice(1,-5) + 'M';
} else {
countStr = countStr.slice(0,-6) + 'M';
}
chrome.tabs.get(tabId, function(tab) {
if ( tab ) {
var pageStats = pageStatsFromTabId(tab.id);
var count = pageStats ? Object.keys(pageStats.requests).length : 0;
var countStr = String(count);
if ( count >= 1000 ) {
if ( count < 10000 ) {
countStr = countStr.slice(0,1) + '.' + countStr.slice(1,-2) + 'K';
} else if ( count < 1000000 ) {
countStr = countStr.slice(0,-3) + 'K';
} else if ( count < 10000000 ) {
countStr = countStr.slice(0,1) + '.' + countStr.slice(1,-5) + 'M';
} else {
countStr = countStr.slice(0,-6) + 'M';
}
}
chrome.browserAction.setBadgeText({ tabId: tab.id, text: countStr });
chrome.browserAction.setBadgeBackgroundColor({ tabId: tab.id, color: '#000' });
}
});
}, 200);
}
chrome.browserAction.setBadgeText({ tabId: tabId, text: countStr });
chrome.browserAction.setBadgeBackgroundColor({ tabId: tabId, color: '#000' });
}

/******************************************************************************/

// Notify whoever care that whitelist/blacklist have changed (they need to
// refresh their matrix).

var permissionsChangedTimer = null;
function permissionChangedCallback() {
chrome.runtime.sendMessage({
'what': 'permissionsChanged'
});
}

function permissionsChanged() {
if ( permissionsChangedTimer ) {
clearTimeout(permissionsChangedTimer);
}
permissionsChangedTimer = setTimeout(function() {
permissionsChangedTimer = null;
chrome.runtime.sendMessage({ 'what': 'permissionsChanged' });
}, 200);
asyncJobQueue.add('permissionsChanged', null, permissionChangedCallback, 250);
}

/******************************************************************************/

// Notify whoever care that url stats have changed (they need to
// rebuild their matrix).

var urlStatsChangedTimers = {};
function urlStatsChangedCallback(pageUrl) {
chrome.runtime.sendMessage({
what: 'urlStatsChanged',
pageUrl: pageUrl
});
}

function urlStatsChanged(pageUrl) {
if ( urlStatsChangedTimers[pageUrl] ) {
clearTimeout(urlStatsChangedTimers[pageUrl]);
}
urlStatsChangedTimers[pageUrl] = setTimeout(function() {
delete urlStatsChangedTimers[pageUrl];
chrome.runtime.sendMessage({
what: 'urlStatsChanged',
pageUrl: pageUrl
});
}, 200);
asyncJobQueue.add('urlStatsChanged ' + pageUrl, pageUrl, urlStatsChangedCallback, 250);
}

/******************************************************************************/

// Handling stuff asynchronously simplifies code

chrome.runtime.onMessage.addListener(function(request, sender, callback) {
function onMessageHandler(request, sender, callback) {
var response;

if ( request && request.what ) {
Expand All @@ -122,17 +181,6 @@ chrome.runtime.onMessage.addListener(function(request, sender, callback) {
startWebRequestHandler(request.from);
break;

case 'updateBadge':
updateBadge(request.pageUrl);
break;

case 'urlStatsChanged':
break;

case 'reloadTabs':
smartReloadTabs();
break;

case 'gotoExtensionUrl':
chrome.tabs.create({'url': chrome.extension.getURL(request.url)});
break;
Expand All @@ -156,5 +204,6 @@ chrome.runtime.onMessage.addListener(function(request, sender, callback) {
if ( callback ) {
callback(response);
}
});
}

chrome.runtime.onMessage.addListener(onMessageHandler);
17 changes: 14 additions & 3 deletions js/cacher.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@

/******************************************************************************/

// rhill 2013-10-23: Commented out since latest fixes
// to URI.js SecondLevelDomains. Not as fast as with the Cacher,
// but now in the upper 0.20 ms on my old crusty laptop, sounds acceptable,
// given the saving in memory footprint.

// This is the solution to avoid calling code which has shown to eat
// too many CPU cycles (profiling showed that URI.js/SLD.has and SLD.is
// are somewhat expensive calls in th context of analyzing net traffic).
Expand All @@ -36,7 +41,7 @@
// : 0.38 ms
// With Cacher: 0.11 ms
// This on an 8 year old Inspiron 6000 running Linux Mint 15 and Chromium 28.

/*
var Cacher = {
questions: {},
ttl: 15 * 60 * 1000,
Expand All @@ -57,6 +62,7 @@ var Cacher = {
},
remember: function(question, response) {
return response;
var entry = this.questions[question];
if ( entry === undefined ) {
this.questions[question] = entry = new this.entry();
Expand All @@ -73,6 +79,7 @@ var Cacher = {
},
exists: function(question) {
return false;
return this.questions[question] !== undefined;
},
Expand All @@ -95,6 +102,10 @@ var Cacher = {
}
};
// purge obsolete questions, those not asked in the last, say, 15 minutes?
setInterval(function(){Cacher.purge();}, Cacher.ttl + 5 * 60 * 1000);
function cacherPurgeCallback() {
Cacher.purge();
}
// purge obsolete questions, those not asked in the last, say, 15 minutes?
asyncJobQueue.add('Cacher.purge()', null, cacherPurgeCallback, Cacher.ttl + 5 * 60 * 1000, true);
*/
8 changes: 7 additions & 1 deletion js/cookies.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,15 @@ var cookieHunter = {
process: function() {
var me = this;
// record cookies from a specific page
// TODO: use internal counter and avoid closures
Object.keys(this.queueRecord).forEach(function(pageUrl) {
chrome.cookies.getAll({}, function(cookies) {
me._record(pageUrl, cookies);
delete me.queueRecord[pageUrl];
});
});
// erase cookies from a specific page
// TODO: use internal counter and avoid closures
Object.keys(this.queueErase).forEach(function(pageUrl) {
chrome.cookies.getAll({}, function(cookies) {
me._erase(pageUrl, cookies);
Expand Down Expand Up @@ -180,7 +182,11 @@ var cookieHunter = {

// Every five seconds, so that cookies are reported soon enough after a
// web page loads.
setInterval(function(){cookieHunter.process();}, 5000);
function cookieHunterCallback() {
cookieHunter.process();
}

asyncJobQueue.add('cookieHunter', null, cookieHunterCallback, 5000, true);

/******************************************************************************/

Expand Down
45 changes: 43 additions & 2 deletions js/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,46 @@
// scripts are blocked, localStorage wont happen.)

// This must be last, so that result is returned to extension.
// This is used so that inline script tags are logged in the stats
!!document.querySelector("script");
// This is used so that inline script tags and preemptively blocked scripts
// (which won't generate web requests) are logged in the stats.
// TODO: Do same with <object>, <embed>, they are currently underreported
// when preemptively blocked.
(function() {
var r = {
pageUrl: window.location.href,
scriptSources: {}, // to avoid duplicates
pluginSources: {} // to avoid duplicates
};
var i, elem, elems;
// https://github.com/gorhill/httpswitchboard/issues/25
elems = document.scripts;
i = elems.length;
while ( i-- ) {
elem = elems[i];
if ( elem.innerText.trim() !== '' ) {
r.scriptSources['{inline_script}'] = true;
}
if ( elem.src && elem.src.trim() !== '' ) {
r.scriptSources[elem.src.trim()] = true;
}
}
// https://github.com/gorhill/httpswitchboard/issues/25
elems = document.querySelectorAll('object');
i = elems.length;
while ( i-- ) {
elem = elems[i];
if ( elem.data && elem.data.trim() !== '' ) {
r.pluginSources[elem.data.trim()] = true;
}
}
// https://github.com/gorhill/httpswitchboard/issues/25
elems = document.querySelectorAll('embed');
i = elems.length;
while ( i-- ) {
elem = elems[i];
if ( elem.src && elem.src.trim() !== '' ) {
r.pluginSources[elem.src.trim()] = true;
}
}
return r;
})();
Loading

0 comments on commit 59ef914

Please sign in to comment.