aboutsummaryrefslogtreecommitdiff
path: root/ext/fiddle
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-05-23 16:54:18 +0000
committerstephan <stephan@noemail.net>2022-05-23 16:54:18 +0000
commit325b56b5049460c04ccf675630d620494f0b1cea (patch)
tree94ca79f4c875628f10a8c6f10a1e1afe3b4f543c /ext/fiddle
parentdc5888e04a2a07e52112a3b0a23520a95fdbba9e (diff)
downloadsqlite-325b56b5049460c04ccf675630d620494f0b1cea.tar.gz
sqlite-325b56b5049460c04ccf675630d620494f0b1cea.zip
fiddle: cleaned up and documented the status-loading progress mechanism in prep for reusing it in the sqlite3-api worker.
FossilOrigin-Name: 107e3497869d757265f2a4235082bf324ba1220075d1096c2a82021a5d348a6c
Diffstat (limited to 'ext/fiddle')
-rw-r--r--ext/fiddle/fiddle-worker.js63
-rw-r--r--ext/fiddle/fiddle.js56
2 files changed, 84 insertions, 35 deletions
diff --git a/ext/fiddle/fiddle-worker.js b/ext/fiddle/fiddle-worker.js
index e2297dbeb..16da63606 100644
--- a/ext/fiddle/fiddle-worker.js
+++ b/ext/fiddle/fiddle-worker.js
@@ -38,19 +38,30 @@
layer. The data property is the string of the output, noting
that the emscripten binding emits these one line at a time. Thus,
if a C-side puts() emits multiple lines in a single call, the JS
- side will see that as multiple calls.
+ side will see that as multiple calls. Example:
+
+ {type:'stdout', data: 'Hi, world.'}
- module: Status text. This is intended to alert the main thread
about module loading status so that, e.g., the main thread can
update a progress widget and DTRT when the module is finished
- loading and available for work. The status text is mostly in some
- undocumented(?) format emited by the emscripten generated
- module-loading code, encoding progress info within it.
+ loading and available for work. Status messages come in the form
+
+ {type:'module', data:{
+ type:'status',
+ data: {text:string|null, step:1-based-integer}
+ }
+
+ with an incrementing step value for each subsequent message. When
+ the module loading is complete, a message with a text value of
+ null is posted.
- working: data='start'|'end'. Indicates that work is about to be
sent to the module or has just completed. This can be used, e.g.,
to disable UI elements which should not be activated while work
- is pending.
+ is pending. Example:
+
+ {type:'working', data:'start'}
Main-to-Worker types:
@@ -60,7 +71,9 @@
it starts and a 'working' event (data='end') when it finished. If
called while work is currently being executed it emits stderr
message instead of doing actual work, as the underlying db cannot
- handle concurrent tasks.
+ handle concurrent tasks. Example:
+
+ {type:'shellExec', data: 'select * from sqlite_master'}
- More TBD as the higher-level db layer develops.
*/
@@ -102,7 +115,40 @@ self.Module = {
//onRuntimeInitialized: function(){},
print: function(text){wMsg('stdout', Array.prototype.slice.call(arguments));},
printErr: function(text){wMsg('stderr', Array.prototype.slice.call(arguments));},
- setStatus: function f(text){wMsg('module',{type:'status',data:text});},
+ /**
+ Intercepts status updates from the Module object and fires
+ worker events with a type of 'status' and a payload of:
+
+ {
+ text: string | null, // null at end of load process
+ step: integer // starts at 1, increments 1 per call
+ }
+
+ We have no way of knowing in advance how many steps will
+ be processed/posted, so creating a "percentage done" view is
+ not really practical. One can be approximated by giving it a
+ current value of message.step and max value of message.step+1,
+ though.
+
+ When work is finished, a message with a text value of null is
+ submitted.
+
+ After a message with text==null is posted, the module may later
+ post messages about fatal problems, e.g. an exit() being
+ triggered, so it is recommended that UI elements for posting
+ status messages not be outright removed from the DOM when
+ text==null, and that they instead be hidden until/unless
+ text!=null.
+ */
+ setStatus: function f(text){
+ if(!f.last) f.last = { step: 0, text: '' };
+ else if(text === f.last.text) return;
+ f.last.text = text;
+ wMsg('module',{
+ type:'status',
+ data:{step: ++f.last.step, text: text||null}
+ });
+ },
totalDependencies: 0,
monitorRunDependencies: function(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
@@ -147,6 +193,5 @@ importScripts('fiddle-module.js')
is called _before_ the final call to Module.setStatus(). */;
Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
- //console.log('onRuntimeInitialized');
- //wMsg('module','done');
+ wMsg('fiddle-ready');
};
diff --git a/ext/fiddle/fiddle.js b/ext/fiddle/fiddle.js
index 30c20a810..2353509da 100644
--- a/ext/fiddle/fiddle.js
+++ b/ext/fiddle/fiddle.js
@@ -17,6 +17,9 @@
(function(){
'use strict';
+ /* Recall that the 'self' symbol, except where locally
+ overwritten, refers to the global window or worker object. */
+
/**
The SqliteFiddle object is intended to be the primary
app-level object for the main-thread side of the sqlite
@@ -136,40 +139,41 @@
SF.addMsgHandler('module', function f(ev){
ev = ev.data;
- //console.log("Module status:",ev);
- if('status'!==ev.type) return;
- /* This weird handling of the ev.data is simply how
- emscripten's auto-generated code notifies the client of
- load progress. */
- let text = ev.data;
- if(!f.last) f.last = { time: Date.now(), text: '' };
- if(text === f.last.text) return;
- const m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
- const now = Date.now();
- if(m && now - f.last.time < 30) return; // if this is a progress update, skip it if too soon
- f.last.time = now;
- f.last.text = text;
- if(m) {
- text = m[1];
- progressElement.value = parseInt(m[2])*100;
- progressElement.max = parseInt(m[4])*100;
+ if('status'!==ev.type){
+ console.warn("Unexpected module-type message:",ev);
+ return;
+ }
+ const msg = ev.data;
+ progressElement.value = msg.step;
+ progressElement.max = msg.step + 1/*we don't know how many steps to expect*/;
+ if(1==msg.step){
progressElement.hidden = false;
spinnerElement.hidden = false;
- } else {
- progressElement.remove();
- if(!text) spinnerElement.remove();
}
- if(text){
- statusElement.innerText = text;
+ if(msg.text){
+ statusElement.classList.remove('hidden');
+ statusElement.innerText = msg.text;
}else{
- console.log("Finalizing status.");
- statusElement.remove();
- SF.clearMsgHandlers('module');
- self.onSFLoaded();
+ progressElement.remove();
+ spinnerElement.remove();
+ statusElement.classList.add('hidden');
+ /* The module can post messages about fatal problems,
+ e.g. an exit() being triggered or assertion failure,
+ after the last "load" message has arrived, so
+ leave the statusElement and message listener intact. */
}
});
/**
+ The 'fiddle-ready' event is fired (with no payload) when the
+ wasm module has finished loading. Interestingly, that happens
+ _before_ the final module:status event */
+ SF.addMsgHandler('fiddle-ready', function(){
+ SF.clearMsgHandlers('fiddle-ready');
+ self.onSFLoaded();
+ });
+
+ /**
Performs all app initialization which must wait until after the
worker module is loaded. This function removes itself when it's
called.