aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-09-27 13:40:12 +0000
committerstephan <stephan@noemail.net>2022-09-27 13:40:12 +0000
commit5b9973d89849c318b0500de1fa0019181e7bd3c0 (patch)
treef6f34298ed88a7fd6a8c6d80f49c4aaae29b73ee /ext/wasm/api
parent3d64548491f6e95854b843f978a4ada16eff614c (diff)
downloadsqlite-5b9973d89849c318b0500de1fa0019181e7bd3c0.tar.gz
sqlite-5b9973d89849c318b0500de1fa0019181e7bd3c0.zip
WASM API renaming. Reworked JS API bootstrap's async post-init into a generic mechanism, no longer OPFS-specific.
FossilOrigin-Name: c42a8cb090cad1108dfd6be574202d744c59e053b505bc4c17252dc6b65d26bf
Diffstat (limited to 'ext/wasm/api')
-rw-r--r--ext/wasm/api/README.md25
-rw-r--r--ext/wasm/api/sqlite3-api-opfs.js12
-rw-r--r--ext/wasm/api/sqlite3-api-prologue.js78
-rw-r--r--ext/wasm/api/sqlite3-api-worker1.js12
-rw-r--r--ext/wasm/api/sqlite3-wasm.c8
5 files changed, 94 insertions, 41 deletions
diff --git a/ext/wasm/api/README.md b/ext/wasm/api/README.md
index 9000697b2..6780c56ae 100644
--- a/ext/wasm/api/README.md
+++ b/ext/wasm/api/README.md
@@ -66,24 +66,33 @@ browser client:
thread via the Worker message-passing interface. Like OO API #1,
this is an optional component, offering one of any number of
potential implementations for such an API.
- - `sqlite3-worker1.js`\
+ - `../sqlite3-worker1.js`\
Is not part of the amalgamated sources and is intended to be
loaded by a client Worker thread. It loads the sqlite3 module
and runs the Worker #1 API which is implemented in
`sqlite3-api-worker1.js`.
+ - `../sqlite3-worker1-promiser.js`\
+ Is likewise not part of the amalgamated sources and provides
+ a Promise-based interface into the Worker #1 API. This is
+ a far user-friendlier way to interface with databases running
+ in a Worker thread.
- `sqlite3-api-opfs.js`\
- is an in-development/experimental sqlite3 VFS wrapper, the goal of
- which being to use Google Chrome's Origin-Private FileSystem (OPFS)
- storage layer to provide persistent storage for database files in a
- browser. It is far from complete.
+ is an sqlite3 VFS implementation which supports Google Chrome's
+ Origin-Private FileSystem (OPFS) as a storage layer to provide
+ persistent storage for database files in a browser. It requires...
+ - `../sqlite3-opfs-async-proxy.js`\
+ is the asynchronous backend part of the OPFS proxy. It speaks
+ directly to the (async) OPFS API and channels those results back
+ to its synchronous counterpart. This file, because it must be
+ started in its own Worker, is not part of the amalgamation.
- `sqlite3-api-cleanup.js`\
the previous files temporarily create global objects in order to
communicate their state to the files which follow them, and _this_
file connects any final components together and cleans up those
globals. As of this writing, this code ensures that the previous
- files leave no global symbols installed, and it moves the sqlite3
- namespace object into the in-scope Emscripten module. Abstracting
- this for other WASM toolchains is TODO.
+ files leave no more than a single global symbol installed. When
+ adapting the API for non-Emscripten toolchains, this "should"
+ be the only file where changes are needed.
- `post-js-footer.js`\
Emscripten-specific footer for the `--post-js` input. This closes
off the lexical scope opened by `post-js-header.js`.
diff --git a/ext/wasm/api/sqlite3-api-opfs.js b/ext/wasm/api/sqlite3-api-opfs.js
index a346443f5..5dac79991 100644
--- a/ext/wasm/api/sqlite3-api-opfs.js
+++ b/ext/wasm/api/sqlite3-api-opfs.js
@@ -20,7 +20,7 @@
'use strict';
self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
- sqlite3.installOpfsVfs() returns a Promise which, on success, installs
+ installOpfsVfs() returns a Promise which, on success, installs
an sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs
which accept a VFS. It uses the Origin-Private FileSystem API for
all file storage. On error it is rejected with an exception
@@ -32,7 +32,6 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- The environment does not support OPFS. That includes when
this function is called from the main window thread.
-
Significant notes and limitations:
- As of this writing, OPFS is still very much in flux and only
@@ -73,8 +72,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
object and that object gets a new object installed in its
`opfs` property, containing several OPFS-specific utilities.
*/
-sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){
- delete sqlite3.installOpfsVfs;
+const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){
if(!self.SharedArrayBuffer ||
!self.FileSystemHandle ||
!self.FileSystemDirectoryHandle ||
@@ -1027,5 +1025,9 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
})/*thePromise*/;
return thePromise;
}/*installOpfsVfs()*/;
-sqlite3.installOpfsVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js";
+installOpfsVfs.defaultProxyUri =
+ //self.location.pathname.replace(/[^/]*$/, "sqlite3-opfs-async-proxy.js");
+ "sqlite3-opfs-async-proxy.js";
+//console.warn("sqlite3.installOpfsVfs.defaultProxyUri =",sqlite3.installOpfsVfs.defaultProxyUri);
+self.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>installOpfsVfs());
}/*sqlite3ApiBootstrap.initializers.push()*/);
diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js
index b2d880937..30e626b67 100644
--- a/ext/wasm/api/sqlite3-api-prologue.js
+++ b/ext/wasm/api/sqlite3-api-prologue.js
@@ -698,8 +698,8 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
["sqlite3_wasm_vfs_unlink", "int", "string"]
];
- /** State for sqlite3_web_persistent_dir(). */
- let __persistentDir;
+ /** State for sqlite3_wasmfs_opfs_dir(). */
+ let __persistentDir = undefined;
/**
An experiment. Do not use in client code.
@@ -713,8 +713,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
This function currently only recognizes the WASMFS/OPFS storage
combination. "Plain" OPFS is provided via a separate VFS which
- can optionally be installed (if OPFS is available on the system)
- using sqlite3.installOpfsVfs().
+ is optionally be installed via sqlite3.asyncPostInit().
TODOs and caveats:
@@ -724,7 +723,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
happen when using the JS-native "opfs" VFS, as opposed to the
WASMFS/OPFS combination.
*/
- capi.sqlite3_web_persistent_dir = function(){
+ capi.sqlite3_wasmfs_opfs_dir = function(){
if(undefined !== __persistentDir) return __persistentDir;
// If we have no OPFS, there is no persistent dir
const pdir = config.wasmfsOpfsDir;
@@ -738,17 +737,6 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
if(pdir && 0===capi.wasm.xCallWrapped(
'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir
)){
- /** OPFS does not support locking and will trigger errors if
- we try to lock. We don't _really_ want to
- _unconditionally_ install a non-locking sqlite3 VFS as the
- default, but we do so here for simplicy's sake for the
- time being. That said: locking is a no-op on all of the
- current WASM storage, so this isn't (currently) as bad as
- it may initially seem. */
- const pVfs = sqlite3.capi.sqlite3_vfs_find("unix-none");
- if(pVfs){
- capi.sqlite3_vfs_register(pVfs,1);
- }
return __persistentDir = pdir;
}else{
return __persistentDir = "";
@@ -762,7 +750,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
/**
Experimental and subject to change or removal.
- Returns true if sqlite3.capi.sqlite3_web_persistent_dir() is a
+ Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a
non-empty string and the given name starts with (that string +
'/'), else returns false.
@@ -771,7 +759,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
kvvfs is available.
*/
capi.sqlite3_web_filename_is_persistent = function(name){
- const p = capi.sqlite3_web_persistent_dir();
+ const p = capi.sqlite3_wasmfs_opfs_dir();
return (p && name) ? name.startsWith(p+'/') : false;
};
@@ -922,11 +910,42 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
}/* main-window-only bits */
+
/* The remainder of the API will be set up in later steps. */
const sqlite3 = {
WasmAllocError: WasmAllocError,
capi,
- config
+ config,
+ /**
+ Performs any optional asynchronous library-level initialization
+ which might be required. This function returns a Promise which
+ resolves to the sqlite3 namespace object. It _ignores any
+ errors_ in the asynchronous init process, as such components
+ are all optional. If called more than once, the second and
+ subsequent calls are no-ops which return a pre-resolved
+ Promise.
+
+ If called at all, this function must be called by client-level
+ code, which must not use the library until the returned promise
+ resolves.
+
+ Bug: if called while a prior call is still resolving, the 2nd
+ call will resolve prematurely, before the 1st call has finished
+ resolving.
+ */
+ asyncPostInit: async function(){
+ let lip = sqlite3ApiBootstrap.initializersAsync;
+ delete sqlite3ApiBootstrap.initializersAsync;
+ if(!lip || !lip.length) return Promise.resolve(sqlite3);
+ // Is it okay to resolve these in parallel or do we need them
+ // to resolve in order? We currently only have 1, so it
+ // makes no difference.
+ lip = lip.map((f)=>f(sqlite3).catch(()=>{}));
+ //let p = lip.shift();
+ //while(lip.length) p = p.then(lip.shift());
+ //return p.then(()=>sqlite3);
+ return Promise.all(lip).then(()=>sqlite3);
+ }
};
sqlite3ApiBootstrap.initializers.forEach((f)=>f(sqlite3));
delete sqlite3ApiBootstrap.initializers;
@@ -946,9 +965,30 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
their features (noting that most will also require that certain
features alread have been installed). At the end of that process,
this array is deleted.
+
+ Note that the order of insertion into this array is significant for
+ some pieces. e.g. sqlite3.capi.wasm cannot be fully utilized until
+ the whwasmutil.js part is plugged in.
*/
self.sqlite3ApiBootstrap.initializers = [];
/**
+ self.sqlite3ApiBootstrap.initializersAsync is an internal detail
+ used by the sqlite3 API's amalgamation process. It must not be
+ modified by client code except when plugging such code into the
+ amalgamation process.
+
+ Counterpart of self.sqlite3ApiBootstrap.initializers, specifically
+ for initializers which are asynchronous. All functions in this list
+ take the sqlite3 object as their argument and MUST return a
+ Promise. Both the resolved value and rejection cases are ignored.
+
+ This list is not processed until the client calls
+ sqlite3.asyncPostInit(). This means, for example, that intializers
+ added to self.sqlite3ApiBootstrap.initializers may push entries to
+ this list.
+*/
+self.sqlite3ApiBootstrap.initializersAsync = [];
+/**
Client code may assign sqlite3ApiBootstrap.defaultConfig an
object-type value before calling sqlite3ApiBootstrap() (without
arguments) in order to tell that call to use this object as its
diff --git a/ext/wasm/api/sqlite3-api-worker1.js b/ext/wasm/api/sqlite3-api-worker1.js
index d9a943971..d60621ada 100644
--- a/ext/wasm/api/sqlite3-api-worker1.js
+++ b/ext/wasm/api/sqlite3-api-worker1.js
@@ -154,12 +154,12 @@
messageId: ...as above...,
result: {
- persistentDirName: path prefix, if any, of persistent storage.
+ wasmfsOpfsDir: path prefix, if any, of persistent storage.
An empty string denotes that no persistent storage is available.
bigIntEnabled: bool. True if BigInt support is enabled.
- persistenceEnabled: true if persistent storage is enabled in the
+ wasmfsOpfsEnabled: true if persistent storage is enabled in the
current environment. Only files stored under persistentDirName
will persist, however.
@@ -183,7 +183,7 @@
See the sqlite3.oo1.DB constructor for peculiarities and transformations,
persistent [=false]: if true and filename is not one of ("",
- ":memory:"), prepend sqlite3.capi.sqlite3_web_persistent_dir()
+ ":memory:"), prepend sqlite3.capi.sqlite3_wasmfs_opfs_dir()
to the given filename so that it is stored in persistent storage
_if_ the environment supports it. If persistent storage is not
supported, the filename is used as-is.
@@ -438,7 +438,7 @@ sqlite3.initWorker1API = function(){
toss("Throwing because of simulateError flag.");
}
const rc = Object.create(null);
- const pDir = sqlite3.capi.sqlite3_web_persistent_dir();
+ const pDir = sqlite3.capi.sqlite3_wasmfs_opfs_dir();
if(!args.filename || ':memory:'===args.filename){
oargs.filename = args.filename || '';
}else if(pDir){
@@ -521,11 +521,11 @@ sqlite3.initWorker1API = function(){
'config-get': function(){
const rc = Object.create(null), src = sqlite3.config;
[
- 'persistentDirName', 'bigIntEnabled'
+ 'wasmfsOpfsDir', 'bigIntEnabled'
].forEach(function(k){
if(Object.getOwnPropertyDescriptor(src, k)) rc[k] = src[k];
});
- rc.persistenceEnabled = !!sqlite3.capi.sqlite3_web_persistent_dir();
+ rc.wasmfsOpfsEnabled = !!sqlite3.capi.sqlite3_wasmfs_opfs_dir();
return rc;
},
diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c
index 8750d9b20..b5b8825d2 100644
--- a/ext/wasm/api/sqlite3-wasm.c
+++ b/ext/wasm/api/sqlite3-wasm.c
@@ -543,9 +543,10 @@ int sqlite3_wasm_vfs_unlink(const char * zName){
return rc;
}
-#if defined(__EMSCRIPTEN__) && defined(SQLITE_WASM_WASMFS)
-#include <emscripten/wasmfs.h>
+#if defined(__EMSCRIPTEN__)
#include <emscripten/console.h>
+#if defined(SQLITE_WASM_WASMFS)
+#include <emscripten/wasmfs.h>
/*
** This function is NOT part of the sqlite3 public API. It is strictly
@@ -596,10 +597,11 @@ int sqlite3_wasm_init_wasmfs(const char *zMountPoint){
#else
WASM_KEEP
int sqlite3_wasm_init_wasmfs(const char *zUnused){
+ emscripten_console_warn("WASMFS OPFS is not compiled in.");
if(zUnused){/*unused*/}
return SQLITE_NOTFOUND;
}
#endif /* __EMSCRIPTEN__ && SQLITE_WASM_WASMFS */
-
+#endif
#undef WASM_KEEP