Browse Source

one pulling if needed is better than always pushing to many + polishing logger

pull/2/head
gorhill 10 years ago
parent
commit
af57d6d9e7
  1. 14
      src/css/logger-ui.css
  2. 19
      src/js/async.js
  3. 75
      src/js/logger-ui.js
  4. 2
      src/js/logger.js
  5. 85
      src/js/messaging.js
  6. 6
      src/js/pagestats.js
  7. 100
      src/js/popup.js

14
src/css/logger-ui.css

@ -141,9 +141,19 @@ body.compactView #content td {
content: '\f070'; content: '\f070';
font: 1em FontAwesome; font: 1em FontAwesome;
} }
body:not(.popupOn) #content table tr.cat_net td:nth-of-type(2) {
#content table tr.tab:not(.canMtx) {
opacity: 0.2;
}
#content table tr.tab:not(.canMtx) > td:nth-of-type(2):before {
content: '\f00d';
font: 1em FontAwesome;
}
body:not(.popupOn) #content table tr.canMtx td:nth-of-type(2) {
cursor: zoom-in; cursor: zoom-in;
} }
body:not(.popupOn) #content table tr.canMtx td:nth-of-type(2):hover {
background: white;
}
#content table tr.cat_net td:nth-of-type(3) { #content table tr.cat_net td:nth-of-type(3) {
font: 12px monospace; font: 12px monospace;
text-align: center; text-align: center;
@ -172,6 +182,8 @@ body.popupOn #popupContainer {
} }
#popupContainer > div { #popupContainer > div {
background: #444; background: #444;
border: 0;
border-bottom: 1px solid white;
cursor: -webkit-grab; cursor: -webkit-grab;
cursor: grab; cursor: grab;
height: 2em; height: 2em;

19
src/js/async.js

@ -172,22 +172,3 @@ return asyncJobManager;
tabIdToTimer[tabId] = setTimeout(updateBadge.bind(this, tabId), 500); tabIdToTimer[tabId] = setTimeout(updateBadge.bind(this, tabId), 500);
}; };
})(); })();
/******************************************************************************/
// Notify whoever care that url stats have changed (they need to
// rebuild their matrix).
µMatrix.urlStatsChanged = function(pageUrl) {
// rhill 2013-11-17: No point in sending this message if the popup menu
// does not exist. I suspect this could be related to
// https://github.com/gorhill/httpswitchboard/issues/58
var urlStatsChangedCallback = function(pageUrl) {
vAPI.messaging.broadcast({
what: 'urlStatsChanged',
pageURL: pageUrl
});
};
this.asyncJobs.add('urlStatsChanged-' + pageUrl, pageUrl, urlStatsChangedCallback, 1000);
};

75
src/js/logger-ui.js

@ -43,6 +43,7 @@ var firstVarDataCol = 2; // currently, column 2 (0-based index)
var lastVarDataIndex = 3; // currently, d0-d3 var lastVarDataIndex = 3; // currently, d0-d3
var maxEntries = 5000; var maxEntries = 5000;
var noTabId = ''; var noTabId = '';
var allTabIds = {};
var prettyRequestTypes = { var prettyRequestTypes = {
'main_frame': 'doc', 'main_frame': 'doc',
@ -167,6 +168,8 @@ var createRow = function(layout) {
var createGap = function(tabId, url) { var createGap = function(tabId, url) {
var tr = createRow('1'); var tr = createRow('1');
tr.classList.add('doc'); tr.classList.add('doc');
tr.classList.add('tab');
tr.classList.add('canMtx');
tr.classList.add('tab_' + tabId); tr.classList.add('tab_' + tabId);
tr.cells[firstVarDataCol].textContent = url; tr.cells[firstVarDataCol].textContent = url;
tbody.insertBefore(tr, tbody.firstChild); tbody.insertBefore(tr, tbody.firstChild);
@ -187,6 +190,7 @@ var renderLogEntry = function(entry) {
case 'net': case 'net':
tr = createRow('111'); tr = createRow('111');
tr.classList.add('canMtx');
// If the request is that of a root frame, insert a gap in the table // If the request is that of a root frame, insert a gap in the table
// in order to visually separate entries for different documents. // in order to visually separate entries for different documents.
if ( entry.d2 === 'doc' && entry.tab !== noTabId ) { if ( entry.d2 === 'doc' && entry.tab !== noTabId ) {
@ -213,10 +217,13 @@ var renderLogEntry = function(entry) {
tr.cells[0].textContent = time.toLocaleTimeString('fullwide', timeOptions); tr.cells[0].textContent = time.toLocaleTimeString('fullwide', timeOptions);
tr.cells[0].title = time.toLocaleDateString('fullwide', dateOptions); tr.cells[0].title = time.toLocaleDateString('fullwide', dateOptions);
if ( entry.tab === noTabId ) {
tr.classList.add('tab_bts');
} else if ( entry.tab !== '' ) {
tr.classList.add('tab_' + entry.tab);
if ( entry.tab ) {
tr.classList.add('tab');
if ( entry.tab === noTabId ) {
tr.classList.add('tab_bts');
} else if ( entry.tab !== '' ) {
tr.classList.add('tab_' + entry.tab);
}
} }
if ( entry.cat !== '' ) { if ( entry.cat !== '' ) {
tr.classList.add('cat_' + entry.cat); tr.classList.add('cat_' + entry.cat);
@ -233,8 +240,6 @@ var renderLogBuffer = function(response) {
return; return;
} }
noTabId = response.noTabId;
// Preserve scroll position // Preserve scroll position
var height = tbody.offsetHeight; var height = tbody.offsetHeight;
@ -276,7 +281,7 @@ var truncateLog = function(size) {
if ( size === 0 ) { if ( size === 0 ) {
size = 5000; size = 5000;
} }
size = Math.min(size, 5000);
size = Math.min(size, 10000);
var tr; var tr;
while ( tbody.childElementCount > size ) { while ( tbody.childElementCount > size ) {
tr = tbody.lastElementChild; tr = tbody.lastElementChild;
@ -286,13 +291,38 @@ var truncateLog = function(size) {
/******************************************************************************/ /******************************************************************************/
var onBufferRead = function(response) {
var onLogBufferRead = function(response) {
// This tells us the behind-the-scene tab id
noTabId = response.noTabId;
// This may have changed meanwhile
if ( response.maxLoggedRequests !== maxEntries ) { if ( response.maxLoggedRequests !== maxEntries ) {
maxEntries = response.maxLoggedRequests; maxEntries = response.maxLoggedRequests;
uDom('#maxEntries').val(maxEntries || ''); uDom('#maxEntries').val(maxEntries || '');
} }
// Neuter rows for which a tab does not exist anymore
// TODO: sort to avoid using indexOf
var targetTabId;
var i = allTabIds.length;
while ( i-- ) {
targetTabId = allTabIds[i];
if ( targetTabId === noTabId ) {
continue;
}
if ( response.allTabIds.indexOf(targetTabId) !== -1 ) {
continue;
}
uDom('.tab_' + targetTabId).removeClass('canMtx');
// Close popup if it is currently inspecting this tab
if ( targetTabId === popupManager.tabId ) {
popupManager.toggleOff();
}
}
allTabIds = response.allTabIds;
renderLogBuffer(response); renderLogBuffer(response);
setTimeout(readLogBuffer, 1000);
setTimeout(readLogBuffer, 1200);
}; };
/******************************************************************************/ /******************************************************************************/
@ -302,7 +332,7 @@ var onBufferRead = function(response) {
// require a bit more code to ensure no multi time out events. // require a bit more code to ensure no multi time out events.
var readLogBuffer = function() { var readLogBuffer = function() {
messager.send({ what: 'readMany' }, onBufferRead);
messager.send({ what: 'readMany' }, onLogBufferRead);
}; };
/******************************************************************************/ /******************************************************************************/
@ -326,7 +356,7 @@ var toggleCompactView = function() {
/******************************************************************************/ /******************************************************************************/
var togglePopup = (function() {
var popupManager = (function() {
var realTabId = null; var realTabId = null;
var localTabId = null; var localTabId = null;
var container = null; var container = null;
@ -337,7 +367,7 @@ var togglePopup = (function() {
var styleTemplate = [ var styleTemplate = [
'tr:not(.tab_{{tabId}}) {', 'tr:not(.tab_{{tabId}}) {',
'cursor: not-allowed;', 'cursor: not-allowed;',
'opacity: 0.1;',
'opacity: 0.2;',
'}' '}'
].join('\n'); ].join('\n');
@ -511,11 +541,24 @@ var togglePopup = (function() {
realTabId = null; realTabId = null;
}; };
return function(ev) {
if ( realTabId === null ) {
toggleOn(ev.target);
var exports = {
toggleOn: function(ev) {
if ( realTabId === null ) {
toggleOn(ev.target);
}
},
toggleOff: function() {
if ( realTabId !== null ) {
toggleOff();
}
} }
}; };
Object.defineProperty(exports, 'tabId', {
get: function() { return realTabId || 0; }
});
return exports;
})(); })();
/******************************************************************************/ /******************************************************************************/
@ -548,7 +591,7 @@ uDom.onLoad(function() {
uDom('#compactViewToggler').on('click', toggleCompactView); uDom('#compactViewToggler').on('click', toggleCompactView);
uDom('#clear').on('click', clearBuffer); uDom('#clear').on('click', clearBuffer);
uDom('#maxEntries').on('change', onMaxEntriesChanged); uDom('#maxEntries').on('change', onMaxEntriesChanged);
uDom('#content table').on('click', 'tr.cat_net > td:nth-of-type(2)', togglePopup);
uDom('#content table').on('click', 'tr.canMtx > td:nth-of-type(2)', popupManager.toggleOn);
}); });
/******************************************************************************/ /******************************************************************************/

2
src/js/logger.js

@ -178,7 +178,7 @@ var writeOne = function() {
/******************************************************************************/ /******************************************************************************/
var readAll = function(tabId) {
var readAll = function() {
if ( logBuffer === null ) { if ( logBuffer === null ) {
logBuffer = new LogBuffer(); logBuffer = new LogBuffer();
setTimeout(janitor, logBufferObsoleteAfter); setTimeout(janitor, logBufferObsoleteAfter);

85
src/js/messaging.js

@ -138,21 +138,23 @@ RowSnapshot.counts = (function() {
/******************************************************************************/ /******************************************************************************/
var matrixSnapshot = function(tabId, details) {
var matrixSnapshot = function(pageStore, details) {
var µmuser = µm.userSettings; var µmuser = µm.userSettings;
var r = { var r = {
tabId: tabId,
url: '',
hostname: '',
domain: '',
blockedCount: 0,
scope: '*',
blockedCount: pageStore.requestStats.blocked.all,
diff: [],
domain: pageStore.pageDomain,
headers: µm.Matrix.getColumnHeaders(), headers: µm.Matrix.getColumnHeaders(),
tSwitches: {},
hostname: pageStore.pageHostname,
mtxContentModifiedTime: pageStore.mtxContentModifiedTime,
mtxCountModifiedTime: pageStore.mtxCountModifiedTime,
pSwitches: {}, pSwitches: {},
rows: {}, rows: {},
rowCount: 0, rowCount: 0,
diff: [],
scope: '*',
tabId: pageStore.tabId,
tSwitches: {},
url: pageStore.pageUrl,
userSettings: { userSettings: {
colorBlindFriendly: µmuser.colorBlindFriendly, colorBlindFriendly: µmuser.colorBlindFriendly,
displayTextSize: µmuser.displayTextSize, displayTextSize: µmuser.displayTextSize,
@ -163,28 +165,8 @@ var matrixSnapshot = function(tabId, details) {
} }
}; };
var tabContext = µm.tabContextManager.lookup(tabId);
// Allow examination of behind-the-scene requests
if (
tabContext.rawURL.lastIndexOf(vAPI.getURL('dashboard.html'), 0) === 0 ||
tabContext.rawURL === µm.behindTheSceneURL
) {
tabId = vAPI.noTabId;
}
var pageStore = µm.pageStoreFromTabId(tabId);
if ( pageStore === null ) {
return r;
}
var headers = r.headers; var headers = r.headers;
r.url = pageStore.pageUrl;
r.hostname = pageStore.pageHostname;
r.domain = pageStore.pageDomain;
r.blockedCount = pageStore.requestStats.blocked.all;
if ( µmuser.popupScopeLevel === 'site' ) { if ( µmuser.popupScopeLevel === 'site' ) {
r.scope = r.hostname; r.scope = r.hostname;
} else if ( µmuser.popupScopeLevel === 'domain' ) { } else if ( µmuser.popupScopeLevel === 'domain' ) {
@ -269,16 +251,46 @@ var matrixSnapshot = function(tabId, details) {
/******************************************************************************/ /******************************************************************************/
var matrixSnapshotFromTabId = function(details, callback) { var matrixSnapshotFromTabId = function(details, callback) {
var matrixSnapshotIf = function(tabId, details) {
var pageStore = µm.pageStoreFromTabId(tabId);
if ( pageStore === null ) {
callback('ENOTFOUND');
return;
}
// First verify whether we must return data or not.
if (
pageStore.mtxContentModifiedTime === details.mtxContentModifiedTime &&
pageStore.mtxCountModifiedTime === details.mtxCountModifiedTime
) {
callback('ENOCHANGE');
return ;
}
callback(matrixSnapshot(pageStore, details));
};
// Specific tab id requested? // Specific tab id requested?
if ( details.tabId ) { if ( details.tabId ) {
callback(matrixSnapshot(details.tabId, details));
matrixSnapshotIf(details.tabId, details);
return; return;
} }
// Otherwise use tab id of current tab
vAPI.tabs.get(null, function(tab) {
callback(matrixSnapshot(tab.id, details));
});
// Fall back to currently active tab
var onTabReady = function(tab) {
if ( typeof tab !== 'object' ) {
callback('ENOTFOUND');
return;
}
// Allow examination of behind-the-scene requests
var tabId = tab.url.lastIndexOf(vAPI.getURL('dashboard.html'), 0) !== 0 ?
tab.id :
vAPI.noTabId;
matrixSnapshotIf(tabId, details);
};
vAPI.tabs.get(null, onTabReady);
}; };
/******************************************************************************/ /******************************************************************************/
@ -962,9 +974,10 @@ var onMessage = function(request, sender, callback) {
case 'readMany': case 'readMany':
response = { response = {
colorBlind: false, colorBlind: false,
entries: µm.logger.readAll(request.tabId),
entries: µm.logger.readAll(),
maxLoggedRequests: µm.userSettings.maxLoggedRequests, maxLoggedRequests: µm.userSettings.maxLoggedRequests,
noTabId: vAPI.noTabId
noTabId: vAPI.noTabId,
allTabIds: Object.keys(µm.pageStores)
}; };
break; break;

6
src/js/pagestats.js

@ -344,6 +344,8 @@ PageStore.prototype.init = function(tabContext) {
this.perLoadAllowedRequestCount = 0; this.perLoadAllowedRequestCount = 0;
this.perLoadBlockedRequestCount = 0; this.perLoadBlockedRequestCount = 0;
this.incinerationTimer = null; this.incinerationTimer = null;
this.mtxContentModifiedTime = 0;
this.mtxCountModifiedTime = 0;
return this; return this;
}; };
@ -397,12 +399,14 @@ PageStore.prototype.recordRequest = function(type, url, block) {
} }
this.distinctRequestCount++; this.distinctRequestCount++;
this.mtxCountModifiedTime = Date.now();
if ( this.domains.hasOwnProperty(hostname) === false ) { if ( this.domains.hasOwnProperty(hostname) === false ) {
this.domains[hostname] = true; this.domains[hostname] = true;
this.allHostnamesString += hostname + ' '; this.allHostnamesString += hostname + ' ';
this.mtxContentModifiedTime = Date.now();
} }
µm.urlStatsChanged(this.pageUrl);
// console.debug("pagestats.js > PageStore.recordRequest(): %o: %s @ %s", this, type, url); // console.debug("pagestats.js > PageStore.recordRequest(): %o: %s @ %s", this, type, url);
}; };

100
src/js/popup.js

@ -67,22 +67,7 @@ var matrixHeaderPrettyNames = {
var firstPartyLabel = ''; var firstPartyLabel = '';
var blacklistedHostnamesLabel = ''; var blacklistedHostnamesLabel = '';
/******************************************************************************/
/******************************************************************************/
// https://github.com/gorhill/httpswitchboard/issues/345
var onMessage = function(msg) {
if ( msg.what !== 'urlStatsChanged' ) {
return;
}
if ( matrixSnapshot.url !== msg.pageURL ) {
return;
}
queryMatrixSnapshot(makeMenu);
};
var messager = vAPI.messaging.channel('popup.js', onMessage);
var messager = vAPI.messaging.channel('popup.js');
/******************************************************************************/ /******************************************************************************/
/******************************************************************************/ /******************************************************************************/
@ -108,7 +93,7 @@ function updateMatrixSnapshot() {
updateMatrixBehavior(); updateMatrixBehavior();
updateMatrixButtons(); updateMatrixButtons();
}; };
queryMatrixSnapshot(snapshotReady);
matrixSnapshotPoller.mustFetch(snapshotReady);
} }
/******************************************************************************/ /******************************************************************************/
@ -1177,35 +1162,80 @@ var onMatrixSnapshotReady = function(response) {
/******************************************************************************/ /******************************************************************************/
var queryMatrixSnapshot = function(callback) {
var tabId = matrixSnapshot.tabId;
var matrixSnapshotPoller = (function() {
var timer = null;
// If no tab id yet, see if there is one specified in our URL
if ( tabId === undefined ) {
var matches = window.location.search.match(/(?:\?|&)tabId=([^&]+)/);
if ( matches !== null ) {
tabId = matches[1];
var snapshotPolled = function(response) {
timer = null;
if ( typeof response === 'object' ) {
matrixSnapshot = response;
makeMenu();
} }
}
pollSnapshotAsync();
};
var request = {
what: 'matrixSnapshot',
tabId: tabId,
tabURL: matrixSnapshot.url
var pollSnapshot = function() {
timer = null;
messager.send({
what: 'matrixSnapshot',
tabId: matrixSnapshot.tabId,
mtxContentModifiedTime: matrixSnapshot.mtxContentModifiedTime,
mtxCountModifiedTime: matrixSnapshot.mtxCountModifiedTime
}, snapshotPolled);
};
var pollSnapshotAsync = function() {
if ( timer !== null ) {
return;
}
timer = setTimeout(pollSnapshot, 1414);
}; };
var snapshotReceived = function(response) {
matrixSnapshot = response;
callback();
var cancelSnapshotAsync = function() {
if ( timer !== null ) {
clearTimeout(timer);
timer = null;
}
}; };
messager.send(request, snapshotReceived);
};
var mustFetch = function(callback) {
cancelSnapshotAsync();
var tabId = matrixSnapshot.tabId;
// If no tab id yet, see if there is one specified in our URL
if ( tabId === undefined ) {
var matches = window.location.search.match(/(?:\?|&)tabId=([^&]+)/);
if ( matches !== null ) {
tabId = matches[1];
}
}
var snapshotFetched = function(response) {
if ( typeof response === 'object' ) {
matrixSnapshot = response;
}
callback();
pollSnapshotAsync();
};
messager.send({
what: 'matrixSnapshot',
tabId: tabId
}, snapshotFetched);
};
return {
mustFetch: mustFetch
};
})();
/******************************************************************************/ /******************************************************************************/
// Make menu only when popup html is fully loaded // Make menu only when popup html is fully loaded
uDom.onLoad(function() { uDom.onLoad(function() {
queryMatrixSnapshot(onMatrixSnapshotReady);
matrixSnapshotPoller.mustFetch(onMatrixSnapshotReady);
// Below is UI stuff which is not key to make the menu, so this can // Below is UI stuff which is not key to make the menu, so this can
// be done without having to wait for a tab to be bound to the menu. // be done without having to wait for a tab to be bound to the menu.

Loading…
Cancel
Save