prevent explosion of scriptsForTab!

This commit is contained in:
Omar Rizwan 2020-12-29 03:52:17 -08:00
parent 44c8dfcec6
commit 705b245be5
3 changed files with 83 additions and 49 deletions

View file

@ -52,24 +52,41 @@ async function detachDebugger(tabId) {
else { resolve(); }
}));
}
const TabManager = {
debugTab: async function(tabId) {
// meant to be higher-level wrapper for raw attach/detach
// TODO: could we remember if we're already attached? idk if it's worth it
try { await attachDebugger(tabId); }
catch (e) {
if (e.message.indexOf('Another debugger is already attached') !== -1) {
await detachDebugger(tabId);
await attachDebugger(tabId);
}
const TabManager = (function() {
if (TESTING) return;
chrome.debugger.onEvent.addListener((source, method, params) => {
console.log(source, method, params);
if (method === "Page.frameStartedLoading") {
// we're gonna assume we're always plugged into both Page and Debugger.
TabManager.scriptsForTab[source.tabId] = [];
} else if (method === "Debugger.scriptParsed") {
TabManager.scriptsForTab[source.tabId] = TabManager.scriptsForTab[source.tabId] || [];
TabManager.scriptsForTab[source.tabId].push(params);
}
// TODO: detach automatically? some kind of reference counting thing?
},
enableDomainForTab: async function(tabId, domain) {
// TODO: could we remember if we're already enabled? idk if it's worth it
await sendDebuggerCommand(tabId, `${domain}.enable`, {});
}
};
});
return {
scriptsForTab: {},
debugTab: async function(tabId) {
// meant to be higher-level wrapper for raw attach/detach
// TODO: could we remember if we're already attached? idk if it's worth it
try { await attachDebugger(tabId); }
catch (e) {
if (e.message.indexOf('Another debugger is already attached') !== -1) {
await detachDebugger(tabId);
await attachDebugger(tabId);
}
}
// TODO: detach automatically? some kind of reference counting thing?
},
enableDomainForTab: async function(tabId, domain) {
// TODO: could we remember if we're already enabled? idk if it's worth it
if (domain === 'Debugger') { TabManager.scriptsForTab[tabId] = []; }
await sendDebuggerCommand(tabId, `${domain}.enable`, {});
}
};
})();
function sendDebuggerCommand(tabId, method, commandParams) {
return new Promise((resolve, reject) =>
chrome.debugger.sendCommand({tabId}, method, commandParams, result => {
@ -78,23 +95,6 @@ function sendDebuggerCommand(tabId, method, commandParams) {
);
}
const BrowserState = { scriptsForTab: {} };
(function() {
if (TESTING) return;
chrome.debugger.onEvent.addListener((source, method, params) => {
console.log(source, method, params);
if (method === "Page.frameStartedLoading") {
// we're gonna assume we're always plugged into both Page and Debugger.
BrowserState.scriptsForTab[source.tabId] = [];
} else if (method === "Debugger.scriptParsed") {
BrowserState.scriptsForTab[source.tabId] = BrowserState.scriptsForTab[source.tabId] || [];
BrowserState.scriptsForTab[source.tabId].push(params);
}
});
})();
const router = {};
const Cache = {
@ -288,14 +288,16 @@ router["/tabs/by-id/*/control"] = {
},
async readdir({path}) {
const tabId = parseInt(pathComponent(path, -3));
return { entries: [".", "..", ...BrowserState.scriptsForTab[tabId].map(params => sanitize(params.url).slice(0, 200) + "_" + params.scriptId)] };
return { entries: [".", "..", ...TabManager.scriptsForTab[tabId].map(params => sanitize(params.url).slice(0, 200) + "_" + params.scriptId)] };
}
};
router["/tabs/by-id/*/debugger/scripts/*"] = defineFile(async path => {
const [tabId, suffix] = [parseInt(pathComponent(path, -4)), pathComponent(path, -1)];
await TabManager.debugTab(tabId);
console.log('BEFORE', TabManager.scriptsForTab[tabId].length);
await TabManager.enableDomainForTab(tabId, "Page");
await TabManager.enableDomainForTab(tabId, "Debugger");
console.log('AFTER', TabManager.scriptsForTab[tabId].length)
const parts = path.split("_"); const scriptId = parts[parts.length - 1];
const {scriptSource} = await sendDebuggerCommand(tabId, "Debugger.getScriptSource", {scriptId});

View file

@ -358,7 +358,18 @@ TODO: make diagrams?
GPLv3
## things that would be cool to do
## things that could/should be done
- add more synthetic files!! view DOM nodes, snapshot current HTML of
page, spelunk into living objects. see what your code is doing. make
more files writable also
- build more (GUI and CLI) tools on top, on both sides
- more persistence stuff
- why can't Preview open images? GUI programs often struggle with the
filesystem for some reason. CLI more reliable
- multithreading. the key constraint is that I pass `-s` to
`fuse_main` in `tabfs.c`, which makes everything
@ -379,18 +390,20 @@ GPLv3
filesystem, even ones you'd assume are reasonably battle-tested and
well-engineered like sshfs?
- other performance stuff -- remembering when we're already attached
to things, reference counting, minimizing browser roundtrips. not
sure impact of these
- TypeScript (how to do with the minimum amount of build system and
package manager nonsense?)
- look into support for Firefox / Windows / Safari / etc. best FUSE
equiv for Windows? can you bridge to the remote debugging APIs that
all of them already have to get the augmented functionality? or just
implement it all with JS monkey patching?
- window management. tab management where you can move tabs
- snapshotting (snapshot.html / snapshot.mhtml file)
- fix leaks
- elim unnecessary round-trips / browser API calls
- window management. tab management where you can move tabs. 'merge
all windows'
## hmm
@ -423,14 +436,30 @@ suggests making an extension is a whole Thing, a whole Project. like,
why can't I just take a minute to ask my browser a question or tell it
to automate something? lightness
- a lot of existing uses of these APIs are in an automation context,
if you want to test your code on an automated browser. I'm much more
interested in an interactive, end-user context. augmenting the way I
use my normal browser. that's why this is an extension. it doesn't
require your browser to run in some weird remote debugging mode that
you'd always forget to turn on. it just [stays
- a lot of existing uses of these APIs are in an automation context:
testing your code on a robotic browser as part of some pipeline. I'm
much more interested in an interactive, end-user context. augmenting
the way I use my everyday browser. that's why this is an
extension. it doesn't require your browser to run in some weird
remote debugging mode that you'd always forget to turn on. it just
[stays
running](https://twitter.com/rsnous/status/1340150818553561094)
- system call tracing (dtruss or strace) super useful when anything is
going wrong. (need to disable SIP on macOS, though.) the
combination of dtruss (application side) & console logging fs
request/response (filesystem side) gives a huge amount of insight
into basically any problem, end to end
- for a lot of things in the extension API, the browser can notify you
of updates but there's no apparent way to query the full current
state. so we'd need to sit in a lot of these places from the
beginning and accumulate the incoming events to know, like, the last
time a tab was updated, or the list of scripts currently running on
a tab
- async/await was absolutely vital to making this readable
- open input space -- filesystem. (it reminds me of Screenotate.)
- now you have this whole 'language', this whole toolset, to control

View file

@ -41,6 +41,9 @@ int main() {
assert(system("echo file://$(pwd)/test-page.html > ../fs/mnt/tabs/create") == 0);
assert(file_contents_equal("../fs/mnt/tabs/last-focused/title.txt", "Title of Test Page"));
assert(file_contents_equal("../fs/mnt/tabs/last-focused/text.txt", "Body Text of Test Page"));
assert(system("ls ../fs/mnt/tabs/last-focused/debugger/scripts") == 0);
assert(system("echo remove > ../fs/mnt/tabs/last-focused/control") == 0);
}