Skip to content

Commit

Permalink
add executables from file system (require store)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcubic committed Aug 16, 2023
1 parent 54e9088 commit 55405d2
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 4 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ SHELL=/bin/bash
CP=cp
TEST=test

all: build
all: build image.z

image.z:
image.z: $(shell find ./root)
./make-image.js -d ./root -f image.z

build: image.z
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The system will run completely in Browser, no Backend. It will be based on FileS
- [ ] Implement Bash.js interpreter using [bash-parser](https://www.npmjs.com/package/bash-parser)
- [ ] Try to make Bash.js part of the Image
- [ ] Add env variables e.g. `$PATH` and `PS1`
- [ ] `[SPIKE]` ESModules with Service Worker inside Web Worker executable
- [x] `[SPIKE]` ESModules with Service Worker inside Web Worker executable
- [ ] Shared libraries as ESModules
- [ ] Bash Commands
- [ ] `cd`
Expand Down
111 changes: 110 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,111 @@ var term;
*/

const { default: MemoryDB } = await import('./MemoryDB.js');

let fs;
let db;
const db_name = '__fs__';
function boot(data) {
db = data ? new MemoryDB(data) : new MemoryDB(db_name);
fs = new LightningFS(db_name, { db });
window.fs = fs;
}
const bs = new BroadcastChannel('rpc');

// -----------------------------------------------------------------------
function is_function(object) {
return get_type(object) === 'function';
}
// -----------------------------------------------------------------------
function is_object(object) {
return object && typeof object === 'object';
}
// -----------------------------------------------------------------------
function is_promise(object) {
return is_object(object) && is_function(object.then || object.done);
}
function get_type(object) {
if (typeof object === 'function') {
return 'function';
}
if (object === null) {
return object + '';
}
if (Array.isArray(object)) {
return 'array';
}
if (typeof object === 'object') {
return 'object';
}
return typeof object;
}

function unpromise(value, callback, error) {
if (is_promise(value)) {
if (is_function(value.catch) && is_function(error)) {
value.catch(error);
}
if (is_function(value.done)) {
return value.done(callback);
} else if (is_function(value.then)) {
return value.then(callback);
}
} else if (value instanceof Array) {
var promises = value.filter(function(value) {
return value && (is_function(value.done) || is_function(value.then));
});
if (promises.length) {
var result = $.when.apply($, value).then(function() {
return callback([].slice.call(arguments));
});
if (is_function(result.catch)) {
result = result.catch(error);
}
return result;
}
}
return callback(value);
}

const namespaces = {
fs: () => fs.promises,
term: () => term
};

bs.addEventListener('message', message => {
const { data } = message;
if (namespaces[data.namespace]) {
const id = data.id;
const object = namespaces[data.namespace]();
unpromise(object[data.method](...data.args), data => {
bs.postMessage({
id,
result: data === term ? null : data
});
}, error => {
bs.postMessage({
id,
error
});
});
}
});

if ('serviceWorker' in navigator) {
const scope = location.pathname.replace(/\/[^\/]+$/, '/');
navigator.serviceWorker.register('sw.js', { scope })
.then(function(reg) {
reg.addEventListener('updatefound', function() {
const installingWorker = reg.installing;
console.log('A new service worker is being installed:',
installingWorker);
});
// registration worked
console.log('Registration succeeded. Scope is ' + reg.scope);
}).catch(function(error) {
// registration failed
console.log('Registration failed with ' + error);
});
}

// --------------------------------------------------------------
Expand Down Expand Up @@ -250,7 +349,17 @@ var term;
if (commands[cmd.name]) {
commands[cmd.name].call(term, cmd);
} else {
term.error('Command not found');
term.pause();
fs.promises.stat(command).then(() => {
const worker = new Worker(`__fs__${command}`);
worker.addEventListener('message', message => {
if (message.data === 'exit') {
resolve();
}
});
}).catch(err => {
term.error(err).resume();
});
}
}
}, {
Expand Down
59 changes: 59 additions & 0 deletions kernel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const bs = new BroadcastChannel('rpc');

let rprc_id = 0;

const modules = new Proxy({}, {
get(target, namespace) {
return new Proxy({}, {
get(target, name) {
return (...args) => {
return new Promise((resolve, reject) => {
const id = ++rprc_id;
const method = name;
bs.addEventListener('message', function handler({data}) {
if (data.id === id) {
if (data.error) {
reject(data.error);
} else {
resolve(data.result);
}
bs.removeEventListener('message', handler);
}
});
bs.postMessage({
id,
namespace,
method,
args
});
});
};
}
});
}
});

let handler_id = 0;
const handlers = {};

function open(filename) {
return new Promise((resolve, reject) => {
fs.stat(filename).then(() => {
const id = ++handler_id;
handlers[id] = filename;
resolve(id);
}).catch(err => {
reject(err);
});
});
}

const kernel_bs = new BroadcastChannel('rpc');

const kernel = {
exec(program) {
return fs.readFile(program).then(code => {
eval(code);
});
}
};
8 changes: 8 additions & 0 deletions process_postfix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
importScripts(location.href.replace(/__fs__.*/, 'kernel.js'));

modules.term.resume().then(() => {
return main();
}).then(code => {
self.postMessage({exit: code});
self.close();
});
7 changes: 7 additions & 0 deletions root/bin/javascript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
async function main() {
const name = await modules.term.read('name: ');
await modules.term.pause();
await modules.term.echo(`Hello ${name}`);
await modules.term.resume();
return 0;
}
24 changes: 24 additions & 0 deletions sw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
importScripts(
'https://cdn.jsdelivr.net/npm/@jcubic/wayne/index.umd.min.js',
'https://cdn.jsdelivr.net/npm/@isomorphic-git/lightning-fs/dist/lightning-fs.min.js',
'https://cdn.jsdelivr.net/gh/jcubic/static@master/js/mime.min.js',
'https://cdn.jsdelivr.net/gh/jcubic/static@master/js/path.js'
);

const { Wayne, FileSystem } = wayne;

const { promises: fs } = new LightningFS('__fs__');

fetch('./process_postfix.js')
.then(res => res.text())
.then(postfix => {
const readFile = fs.readFile;
fs.readFile = async function(...args) {
const output = await readFile(...args);
return `${output}\n${postfix}`;
};
});

const app = new Wayne();

app.use(FileSystem({ path, fs, mime, prefix: '__fs__' }));

0 comments on commit 55405d2

Please sign in to comment.