diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index ed3f9cbeff0c2..034b8753e889a 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -865,6 +865,21 @@ Asynchronous IndexedDB API - *(void*)* : Equal to ``arg`` (user defined data). +.. c:function:: void emscripten_idb_async_clear(const char *db_name, void* arg, em_arg_callback_func onclear, em_arg_callback_func onerror) + + Clears all data from local IndexedDB storage asynchronously. + + When the storage has been cleared then the ``onclear`` callback will be called. If any error occurred ``onerror`` will be called. + + :param db_name: The IndexedDB database. + :param void* arg: User-defined data that is passed to the callbacks, untouched by the API itself. This may be used by a callback to identify the associated call. + :param em_arg_callback_func onclear: Callback on successful clear. The callback function parameter is: + + - *(void*)* : Equal to ``arg`` (user defined data). + + :param em_arg_callback_func onerror: Callback in the event of failure. The callback function parameter is: + + - *(void*)* : Equal to ``arg`` (user defined data). .. c:function:: int emscripten_run_preload_plugins(const char* file, em_str_callback_func onload, em_str_callback_func onerror) @@ -1362,6 +1377,13 @@ IndexedDB :param pexists: An out parameter that will be filled with a non-zero value if the file exists in that database. :param perror: An out parameter that will be filled with a non-zero value if an error occurred. +.. c:function:: void emscripten_idb_clear(const char *db_name, int *perror); + + Synchronously clears all data from IndexedDB. + + :param db_name: The name of the database to clear + :param perror: An out parameter that will be filled with a non-zero value if an error occurred. + Upstream Asyncify functions =========================== diff --git a/src/IDBStore.js b/src/IDBStore.js index cbba508d02748..355d23559217d 100644 --- a/src/IDBStore.js +++ b/src/IDBStore.js @@ -102,4 +102,12 @@ var IDBStore = { req.onerror = (error) => callback(error); }); }, + clearStore(dbName, callback) { + IDBStore.getStore(dbName, 'readwrite', (err, store) => { + if (err) return callback(err); + var req = store.clear(); + req.onsuccess = (event) => callback(); + req.onerror = (error) => callback(error); + }); + }, }; diff --git a/src/library_idbstore.js b/src/library_idbstore.js index d63f141c0d042..0cadef29066fe 100644 --- a/src/library_idbstore.js +++ b/src/library_idbstore.js @@ -76,6 +76,20 @@ var LibraryIDBStore = { }); }); }, + emscripten_idb_async_clear__deps: ['$UTF8ToString', '$callUserCallback'], + emscripten_idb_async_clear: (db, arg, onclear, onerror) => { + {{{ runtimeKeepalivePush() }}}; + IDBStore.clearStore(UTF8ToString(db), (error) => { + {{{ runtimeKeepalivePop() }}} + callUserCallback(() => { + if (error) { + if (onerror) {{{ makeDynCall('vp', 'onerror') }}}(arg); + return; + } + if (onclear) {{{ makeDynCall('vp', 'onclear') }}}(arg); + }); + }); + }, #if ASYNCIFY emscripten_idb_load__async: true, @@ -125,6 +139,15 @@ var LibraryIDBStore = { }); }); }, + emscripten_idb_clear__async: true, + emscripten_idb_clear: (db, perror) => { + return Asyncify.handleSleep((wakeUp) => { + IDBStore.clearStore(UTF8ToString(db), (error) => { + {{{ makeSetValue('perror', 0, '!!error', 'i32') }}}; + wakeUp(); + }); + }); + }, // extra worker methods - proxied emscripten_idb_load_blob__async: true, emscripten_idb_load_blob: (db, id, pblob, perror) => { @@ -195,6 +218,9 @@ var LibraryIDBStore = { emscripten_idb_exists: (db, id, pexists, perror) => { throw 'Please compile your program with async support in order to use synchronous operations like emscripten_idb_exists, etc.'; }, + emscripten_idb_clear: (db, perror) => { + throw 'Please compile your program with async support in order to use synchronous operations like emscripten_idb_clear, etc.'; + }, #endif // ASYNCIFY }; diff --git a/src/library_sigs.js b/src/library_sigs.js index ff58c856b8272..6fc8f32a389c9 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -650,10 +650,12 @@ sigs = { emscripten_has_threading_support__sig: 'i', emscripten_hide_mouse__sig: 'v', emscripten_html5_remove_all_event_listeners__sig: 'v', + emscripten_idb_async_clear__sig: 'vpppp', emscripten_idb_async_delete__sig: 'vppppp', emscripten_idb_async_exists__sig: 'vppppp', emscripten_idb_async_load__sig: 'vppppp', emscripten_idb_async_store__sig: 'vpppippp', + emscripten_idb_clear__sig: 'vpp', emscripten_idb_delete__sig: 'vppp', emscripten_idb_exists__sig: 'vpppp', emscripten_idb_load__sig: 'vppppp', diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index fe898165cd316..8d5e347b2fa65 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -95,6 +95,7 @@ void emscripten_idb_async_store(const char *db_name __attribute__((nonnull)), co void emscripten_idb_async_delete(const char *db_name __attribute__((nonnull)), const char *file_id __attribute__((nonnull)), void* arg, em_arg_callback_func ondelete, em_arg_callback_func onerror); typedef void (*em_idb_exists_func)(void*, int); void emscripten_idb_async_exists(const char *db_name __attribute__((nonnull)), const char *file_id __attribute__((nonnull)), void* arg, em_idb_exists_func oncheck, em_arg_callback_func onerror); +void emscripten_idb_async_clear(const char *db_name __attribute__((nonnull)), void* arg, em_arg_callback_func onclear, em_arg_callback_func onerror); // IDB "sync" @@ -102,6 +103,7 @@ void emscripten_idb_load(const char *db_name, const char *file_id, void** pbuffe void emscripten_idb_store(const char *db_name, const char *file_id, void* buffer, int num, int *perror); void emscripten_idb_delete(const char *db_name, const char *file_id, int *perror); void emscripten_idb_exists(const char *db_name, const char *file_id, int* pexists, int *perror); +void emscripten_idb_clear(const char *db_name, int *perror); void emscripten_idb_load_blob(const char *db_name, const char *file_id, int* pblob, int *perror); void emscripten_idb_store_blob(const char *db_name, const char *file_id, void* buffer, int num, int *perror); diff --git a/test/browser/test_idbstore.c b/test/browser/test_idbstore.c index e41e476d8dda9..4f7f354c79655 100644 --- a/test/browser/test_idbstore.c +++ b/test/browser/test_idbstore.c @@ -77,6 +77,10 @@ int main() { #elif STAGE == 5 expected = 77; emscripten_idb_async_exists(DB, "the_secret", (void*)expected, onchecknope, onerror); +#elif STAGE == 6 + expected = 88; + printf("clearing\n"); + emscripten_idb_async_clear(DB, (void*)expected, ok, onerror); #else assert(0); #endif diff --git a/test/browser/test_idbstore_sync.c b/test/browser/test_idbstore_sync.c index e2a21a65ad491..f3aaceb0331f4 100644 --- a/test/browser/test_idbstore_sync.c +++ b/test/browser/test_idbstore_sync.c @@ -52,6 +52,16 @@ void test() { assert(error); // expected error! sum++; + printf("storing %s again\n", SECRET); + emscripten_idb_store(DB, "the_secret", SECRET, strlen(SECRET)+1, &error); + assert(!error); + sum++; + + printf("clearing the store\n"); + emscripten_idb_clear(DB, &error); + assert(!error); + sum++; + printf("last checking\n"); emscripten_idb_exists(DB, "the_secret", &exists, &error); assert(!error); diff --git a/test/browser/test_idbstore_sync_worker.c b/test/browser/test_idbstore_sync_worker.c index 2ea1a90c65c3d..150a50659cf6f 100644 --- a/test/browser/test_idbstore_sync_worker.c +++ b/test/browser/test_idbstore_sync_worker.c @@ -50,6 +50,16 @@ int main() { assert(error); // expected error! sum++; + printf("storing %s again\n", SECRET); + emscripten_idb_store(DB, "the_secret", SECRET, strlen(SECRET)+1, &error); + assert(!error); + sum++; + + printf("clearing the store\n"); + emscripten_idb_clear(DB, &error); + assert(!error); + sum++; + printf("last checking\n"); emscripten_idb_exists(DB, "the_secret", &exists, &error); assert(!error); @@ -93,7 +103,7 @@ int main() { // finish up - assert(sum == 6); + assert(sum == 8); REPORT_RESULT(0); return 0; } diff --git a/test/test_browser.py b/test/test_browser.py index 3b066d13a3a95..12bd6420e3d21 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -1505,7 +1505,7 @@ def test_separate_metadata_later(self): @also_with_wasm64 def test_idbstore(self): secret = str(time.time()) - for stage in [0, 1, 2, 3, 0, 1, 2, 0, 0, 1, 4, 2, 5]: + for stage in [0, 1, 2, 3, 0, 1, 2, 0, 0, 1, 4, 2, 5, 0, 4, 6, 5]: print(stage) self.btest_exit('test_idbstore.c', args=['-lidbstore.js', f'-DSTAGE={stage}', f'-DSECRET="{secret}"'], @@ -1524,7 +1524,7 @@ def test_idbstore_sync(self, asyncify, wasm64): if asyncify == 2: self.require_jspi() secret = str(time.time()) - self.btest('test_idbstore_sync.c', '6', args=['-lidbstore.js', f'-DSECRET="{secret}"', '-O3', '-g2', '-sASYNCIFY=' + str(asyncify)]) + self.btest('test_idbstore_sync.c', '8', args=['-lidbstore.js', f'-DSECRET="{secret}"', '-O3', '-g2', '-sASYNCIFY=' + str(asyncify)]) def test_idbstore_sync_worker(self): secret = str(time.time())