aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOmar Rizwan <omar@omar.website>2020-12-24 23:46:48 -0800
committerOmar Rizwan <omar@omar.website>2020-12-24 23:46:48 -0800
commit462a657bfd61840ea05f615bc38759d8832c49c1 (patch)
tree73053b8cd0168a62107a4e25e54d6d4c3ba80f95
parent2a67a62e2167f60138dc875552634ae549a5c7f9 (diff)
remove doc/README. fix truncate on extensions/*/enabled. add timeout
-rw-r--r--README.md238
-rw-r--r--doc/finder-contents.pngbin267777 -> 0 bytes
-rw-r--r--doc/finder.pngbin889669 -> 0 bytes
-rw-r--r--doc/inspector.pngbin1021819 -> 0 bytes
-rw-r--r--extension/background.js39
-rwxr-xr-xtest.c2
6 files changed, 33 insertions, 246 deletions
diff --git a/README.md b/README.md
index 0aefbcc..035bf09 100644
--- a/README.md
+++ b/README.md
@@ -1,239 +1,3 @@
# TabFS
-TabFS is a browser extension that mounts your browser tabs as a
-filesystem on your computer.
-
-Out of the box, it supports Chrome and (to a lesser extent) Firefox,
-on macOS and Linux; it could probably be made to work on other
-browsers like Safari and Opera that support the WebExtensions API, but
-I haven't looked into it.
-
-<img src="doc/finder.png" width="500">
-
-Each of your open tabs is mapped to a folder with a bunch of files
-inside it. These files directly reflect (and can control) the state of
-that tab. (TODO: update as I add more)
-
-<img src="doc/finder-contents.png" width="500">
-
-This gives you a _ton_ of power, because now you can apply [all the
-existing tools](https://twitter.com/rsnous/status/1018570020324962305)
-on your computer that already know how to deal with files -- terminal
-commands, scripting languages, etc -- and use them to control and draw
-information out of your browser. You don't need to code up a browser
-extension from scratch every time you want to do anything.
-
-## Examples of stuff you can do!
-
-(assuming your shell is in the `fs` subdirectory of this repo)
-
-(TODO: more of these)
-
-### List the titles of all the tabs you have open
-
-```
-$ cat mnt/tabs/by-id/*/title
-GitHub
-Extensions
-TabFS/install.sh at master ยท osnr/TabFS
-Alternative Extension Distribution Options - Google Chrome
-Web Store Hosting and Updating - Google Chrome
-Home / Twitter
-...
-```
-
-### Close all Stack Overflow tabs
-
-```
-$ rm mnt/tabs/by-title/*Stack_Overflow*
-```
-
-or (older)
-
-```
-$ echo remove | tee -a mnt/tabs/by-title/*Stack_Overflow*/control
-```
-
-### Save text of all tabs to a file
-
-```
-$ cat mnt/tabs/by-id/*/text > text.txt
-```
-
-### TODO: Reload an extension when you edit its source code
-
-Making another extension?
-
-SO post.
-
-We can subsume that.
-
-### TODO: Manage tabs in Emacs dired
-
-I do this
-
-### TODO: Live edit
-
-
-
-### TODO: Something with live view of variables
-
-
-## Setup
-
-**disclaimer**: security, functionality, blah blah. applications may
-freeze ... In some sense, the whole point of this extension is to
-create a gigantic new surface area of communication between stuff
-inside your browser and software on the rest of your computer.
-
-First, install the browser extension.
-
-Then, install the C filesystem.
-
-### 1. Install the browser extension
-
-(I think for Opera or whatever other Chromium-based browser, you could
-get it to work, but you'd need to change the native messaging path in
-install.sh. Not sure about Safari. maybe Edge too? if you also got
-everything to compile for Windows)
-
-#### in Chrome
-
-Go to the [Chrome extensions page](chrome://extensions). Enable
-Developer mode (top-right corner).
-
-Load-unpacked the `extension/` folder in this repo.
-
-**Make a note of the extension ID Chrome assigns.** Mine is
-`jimpolemfaeckpjijgapgkmolankohgj`. We'll use this later.
-
-#### in Firefox
-
-You'll need to install as a "temporary extension", so it'll only last
-in your current FF session.
-
-Go to [about:debugging#/runtime/this-firefox](about:debugging#/runtime/this-firefox).
-
-Load Temporary Add-on...
-
-Choose manifest.json in the extension subfolder of this repo.
-
-### 2. Install the C filesystem
-
-First, make sure you `git submodule update --init` to get the
-`fs/cJSON` and `fs/base64` dependencies.
-
-And make sure you have FUSE. On Linux, for example, `sudo apt install
-libfuse-dev`. On macOS, get FUSE for macOS.
-
-```
-$ cd fs
-$ mkdir mnt
-$ make
-```
-
-Now install the native messaging host into your browser, so the
-extension can launch and talk to the filesystem:
-
-#### Chrome and Chromium
-
-Substitute the extension ID you copied earlier for
-`jimpolemfaeckpjijgapgkmolankohgj` in the command below.
-
-```
-$ ./install.sh chrome jimpolemfaeckpjijgapgkmolankohgj
-```
-
-or
-
-```
-$ ./install.sh chromium jimpolemfaeckpjijgapgkmolankohgj
-```
-
-### 3. Ready!
-
-Go back to `chrome://extensions` or
-`about:debugging#/runtime/this-firefox` and reload the extension.
-
-Now your browser tabs should be mounted in `fs/mnt`!
-
-Open the background page inspector to see the filesystem operations
-stream in. (in Chrome, click "background page" next to "Inspect views"
-in the extension's entry in the Chrome extensions page; in Firefox,
-click "Inspect")
-
-<img src="doc/inspector.png" width="600">
-
-This console is also incredibly helpful for debugging anything that
-goes wrong, which probably will happen.
-
-(My OS and applications are pretty chatty! They do a lot of
-operations, even when I don't feel like I'm actually doing anything.)
-
-## Design
-
-- `fs/`: Native FUSE filesystem, written in C
- - [`tabfs.c`](fs/tabfs.c): Talks to FUSE, implements fs operations, talks to extension.
-- `extension/`: Browser extension, written in JS
- - [`background.js`](extension/background.js): **The most interesting
- file**. Defines all the synthetic files and what browser
- operations they invoke behind the scenes.
-
-<!-- TODO: concretize this -->
-
-When you, say, `cat` a file in the tab filesystem:
-
-1. `cat` makes something like a `read` syscall,
-
-2. which goes to the FUSE kernel module which backs that filesystem,
-
-3. FUSE forwards it to the `tabfs_read` implementation in our
- userspace filesystem in `fs/tabfs.c`,
-
-4. then `tabfs_read` rephrases the request as a JSON string and
- forwards it to the browser extension over 'native messaging',
-
-6. our browser extension in `extension/background.js` handles the
- incoming message and calls the browser APIs to construct the data
- for that synthetic file;
-
-7. then the data gets sent back in a JSON native message to `tabfs.c`
- and and finally back to FUSE and the kernel and `cat`.
-
-(very little actual work happened here, tbh. it's all just
-marshalling)
-
-TODO: make diagrams?
-
-## license
-
-GPLv3
-
-## hmm
-
-processes as files. the real process is the browser.
-
-browser and Unix; the two operating systems
-
-it's way too hard to make an extension. even 'make an extension' is a
-bad framing; it 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
-
-open input space -- filesystem
-
-now you have this whole 'language', this whole toolset, to control and
-automate your browser. there's this built-up existing capital where
-lots of people already know the operations to work with files
-
-this project is cool bc i immediately get a dataset i care about
-
-OSQuery
-
-fake filesystems talk
-
-Screenotate
-
-rmdir a non-empty directory
-
-do you like setting up sockets? I don't
+See [https://omar.website/tabfs/].
diff --git a/doc/finder-contents.png b/doc/finder-contents.png
deleted file mode 100644
index 71767a8..0000000
--- a/doc/finder-contents.png
+++ /dev/null
Binary files differ
diff --git a/doc/finder.png b/doc/finder.png
deleted file mode 100644
index 3006399..0000000
--- a/doc/finder.png
+++ /dev/null
Binary files differ
diff --git a/doc/inspector.png b/doc/inspector.png
deleted file mode 100644
index c0afa19..0000000
--- a/doc/inspector.png
+++ /dev/null
Binary files differ
diff --git a/extension/background.js b/extension/background.js
index 700d0ad..ecba875 100644
--- a/extension/background.js
+++ b/extension/background.js
@@ -8,6 +8,7 @@ const unix = {
EIO: 5,
ENXIO: 6,
ENOTSUP: 45,
+ ETIMEDOUT: 110,
// Unix file types
S_IFMT: 0170000, // type of file mask
@@ -215,6 +216,17 @@ router["/tabs/by-id"] = {
router["/tabs/by-id/*/url"] = withTab(tab => tab.url + "\n", buf => ({ url: buf }));
router["/tabs/by-id/*/title"] = withTab(tab => tab.title + "\n");
router["/tabs/by-id/*/text"] = fromScript(`document.body.innerText`);
+ router["/tabs/by-id/*/console"] = {
+ open() {
+ // inject the console
+ },
+ read() {
+
+ },
+ write() {
+ // what does this even do?
+ }
+ }
})();
router["/tabs/by-id/*/screenshot.png"] = defineFile(async path => {
const tabId = parseInt(pathComponent(path, -2));
@@ -278,7 +290,6 @@ router["/tabs/by-id/*/scripts/*"] = defineFile(async path => {
await sendDebuggerCommand(tabId, "Debugger.setScriptSource", {scriptId, scriptSource: buf});
return {};
});
-
router["/tabs/by-id/*/control"] = {
// echo remove >> mnt/tabs/by-id/1644/control
async write({path, buf}) {
@@ -295,7 +306,7 @@ router["/tabs/by-id/*/control"] = {
router["/tabs/by-title"] = {
getattr() {
return {
- st_mode: unix.S_IFDIR | 0777,
+ st_mode: unix.S_IFDIR | 0777, // writable
st_nlink: 3,
st_size: 0,
};
@@ -311,7 +322,7 @@ router["/tabs/by-title/*"] = {
const parts = path.split("_"); const tabId = parts[parts.length - 1];
return { buf: "../by-id/" + tabId };
},
- async unlink({path}) {
+ async unlink({path}) { // you can delete a by-title/TAB to close that tab
const parts = path.split("_"); const tabId = parseInt(parts[parts.length - 1]);
await browser.tabs.remove(tabId);
return {};
@@ -332,16 +343,17 @@ router["/extensions"] = {
return { entries: [".", "..", ...infos.map(info => `${sanitize(info.name)}_${info.id}`)] };
}
};
-router["/extensions/*/enabled"] = defineFile(async path => {
+router["/extensions/*/enabled"] = { ...defineFile(async path => {
const parts = pathComponent(path, -2).split('_'); const extensionId = parts[parts.length - 1];
const info = await browser.management.get(extensionId);
return String(info.enabled) + '\n';
}, async (path, buf) => {
- console.log(buf);
const parts = pathComponent(path, -2).split('_'); const extensionId = parts[parts.length - 1];
await browser.management.setEnabled(extensionId, buf.trim() === "true");
-});
+
+ // suppress truncate so it doesn't accidentally flip the state when you do, e.g., `echo true >`
+}), truncate() { return {}; } };
router["/runtime/reload"] = {
async write({path, buf}) {
@@ -466,6 +478,13 @@ async function onMessage(req) {
console.log('req', req);
let response = { op: req.op, error: unix.EIO };
+ let didTimeout = false, timeout = setTimeout(() => {
+ // timeout is very useful because some operations just hang
+ // (like trying to take a screenshot, until the tab is focused)
+ didTimeout = true; console.error('timeout');
+ port.postMessage({ op: req.op, error: unix.ETIMEDOUT });
+ }, 1000);
+
/* console.time(req.op + ':' + req.path);*/
try {
response = await findRoute(req.path)[req.op](req);
@@ -481,8 +500,12 @@ async function onMessage(req) {
}
/* console.timeEnd(req.op + ':' + req.path);*/
- console.log('resp', response);
- port.postMessage(response);
+ if (!didTimeout) {
+ clearTimeout(timeout);
+
+ console.log('resp', response);
+ port.postMessage(response);
+ }
};
function tryConnect() {
diff --git a/test.c b/test.c
index c57f0b6..9f6c14b 100755
--- a/test.c
+++ b/test.c
@@ -24,7 +24,7 @@ char* expand(char* phrase) {
int main() {
assert(system("echo about:blank > fs/mnt/tabs/create") == 0);
assert(file_contents_equal("fs/mnt/tabs/last-focused/url", "about:blank"));
- /* assert(system("file fs/mnt/tabs/last-focused/screenshot.png") == 0); */
+ assert(system("file fs/mnt/tabs/last-focused/screenshot.png") == 0); // slow
assert(system("echo remove > fs/mnt/tabs/last-focused/control") == 0);
assert(file_contents_equal(expand("fs/mnt/extensions/TabFS*/enabled"), "true"));