mesh app work. improve script setup

This commit is contained in:
Stewart Allen 2021-12-26 19:43:48 -05:00
commit 16fa536605
8 changed files with 286 additions and 86 deletions

View file

@ -1,10 +1,14 @@
// required for license and other grid app dependencies
self.gapp = {};
self.gapp = self.gapp || {};
function $(id) {
return document.getElementById(id);
}
function $d(id, v) {
$(id).style.display = v;
}
function init() {
let container = $('container'),
moto = self.moto,
@ -28,10 +32,13 @@ function init() {
Space.useDefaultKeys(true);
// hide loading curtain
$('curtain').style.display = 'none';
$d('curtain','none');
// remove version cache bust from url
window.history.replaceState({},'','/mesh/');
// start worker
moto.client.start(`/code/mesh_work?${gapp.version}`);
}
document.onreadystatechange = function() {

124
src/moto/client.js Normal file
View file

@ -0,0 +1,124 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
"use strict";
(function() {
let MOTO = self.moto = self.moto || {},
time = function() { return new Date().getTime() },
restarting = false,
running = {},
workurl = null,
worker = null,
seqid = 1;
/**
* @param {Function} fn name of function in MOTO.worker
* @param {Object} data to send to server
* @param {Function} onreply function to call on reply messages
* @param {Object[]} zerocopy array of objects to pass using zerocopy
*/
function send(fn, data, onreply, zerocopy) {
let seq = seqid++;
if (onreply) {
// establish listener and track replies
running[seq] = { fn:onreply };
}
let msg = {
seq: seq,
task: fn,
time: time(),
data: data
};
try {
worker.postMessage(msg, zerocopy);
} catch (error) {
console.trace('work send error', {data, error});
}
}
// code is running in the browser / client context
let CLIENT = MOTO.client = {
send: send,
// factory can be overridden
newWorker: function(url = workurl) {
if (self.createWorker) {
return self.createWorker();
} else {
return new Worker(workurl = url);
}
},
// return number of running requests
current: function() {
let current = 0;
for (let rec of Object.values(running)) {
if (rec.fn) current++;
}
return current;
},
stop: function() {
if (worker) {
worker.terminate();
worker = null;
}
},
// same as restart
start: function(url) {
CLIENT.restart(url);
},
restart: function(url) {
// prevent re-entry from cancel callback
if (restarting) {
return;
}
CLIENT.stop();
restarting = true;
for (let key in running) {
let rec = running[key];
if (rec.fn) {
rec.fn({error: "cancelled operation"});
}
}
running = {};
worker = CLIENT.newWorker(url);
// bind to CLIENT to enable synth injections
CLIENT.onmessage = worker.onmessage = function(e) {
let now = time(),
reply = e.data,
record = running[reply.seq],
onreply = record ? record.fn : undefined;
if (reply.done) {
delete running[reply.seq];
}
// calculate and replace recv time
reply.time_recv = now - reply.time_recv;
if (onreply) {
onreply(reply.data, reply);
} else {
console.log({drop_reply: reply});
}
};
// signal worker client is ready
worker.postMessage("--init--");
restarting = false;
}
};
})();

80
src/moto/worker.js Normal file
View file

@ -0,0 +1,80 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
"use strict";
(function() {
let MOTO = self.moto = self.moto || {},
time = Date.now;
// allow license to inject module
self.gapp = self.gapp || MOTO;
// code is running in the worker / server context
const dispatch = MOTO.worker = {
send: (msg) => {
self.postMessage(msg);
},
onmessage: (e) => {
if (e.data === '--init--') {
console.log('worker got init');
return;
}
let time_recv = time(),
msg = e.data || {},
run = dispatch[msg.task],
send = {
data : function(data,direct) {
dispatch.send({
seq: msg.seq,
task: msg.task,
done: false,
data: data
}, direct);
},
done : function(data,direct) {
dispatch.send({
seq: msg.seq,
task: msg.task,
done: true,
data: data
}, direct);
}
};
if (run) {
try {
let time_xfer = (time_recv - msg.time),
output = run(msg.data, send),
time_send = time(),
time_proc = time_send - time_recv;
if (output) dispatch.send({
seq: msg.seq,
task: msg.task,
time_send: time_xfer,
time_proc: time_proc,
// replaced on reply side
time_recv: time(),
data: output
});
} catch (wrkerr) {
// console.log(wrkerr);
console.trace(wrkerr.stack);
send.done({error: wrkerr.toString()});
}
} else {
console.log({worker_unhandled: e, msg, fn: dispatch[msg.task]});
}
}
};
// attach onmessage hanler
self.onmessage = dispatch.onmessage;
})();