aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/library_fs.js84
-rw-r--r--tests/file_db.cpp47
-rw-r--r--tests/test_browser.py11
3 files changed, 142 insertions, 0 deletions
diff --git a/src/library_fs.js b/src/library_fs.js
index e1397356..9c8223ab 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -802,6 +802,90 @@ mergeInto(LibraryManager.library, {
}
},
+ indexedDB: function() {
+ return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+ },
+
+ DB_NAME: function() {
+ return 'EM_FS_' + window.location.pathname;
+ },
+ DB_VERSION: 20,
+ DB_STORE_NAME: 'FILE_DATA',
+
+ // asynchronously saves a list of files to an IndexedDB. The DB will be created if not already existing.
+ saveFilesToDB: function(paths, onload, onerror) {
+ onload = onload || function(){};
+ onerror = onerror || function(){};
+ var indexedDB = FS.indexedDB();
+ try {
+ var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+ } catch (e) {
+ return onerror(e);
+ }
+ openRequest.onupgradeneeded = function() {
+ console.log('creating db');
+ var db = openRequest.result;
+ db.createObjectStore(FS.DB_STORE_NAME);
+ };
+ openRequest.onsuccess = function() {
+ var db = openRequest.result;
+ var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+ var files = transaction.objectStore(FS.DB_STORE_NAME);
+ var ok = 0, fail = 0, total = paths.length;
+ function finish() {
+ if (fail == 0) onload(); else onerror();
+ }
+ paths.forEach(function(path) {
+ var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+ putRequest.onsuccess = function() { ok++; if (ok + fail == total) finish() };
+ putRequest.onerror = function() { fail++; if (ok + fail == total) finish() };
+ });
+ transaction.onerror = onerror;
+ };
+ openRequest.onerror = onerror;
+ },
+
+ // asychronously loads a file from IndexedDB.
+ loadFilesFromDB: function(paths, onload, onerror) {
+ onload = onload || function(){};
+ onerror = onerror || function(){};
+ var indexedDB = FS.indexedDB();
+ try {
+ var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+ } catch (e) {
+ return onerror(e);
+ }
+ openRequest.onupgradeneeded = onerror; // no database to load from
+ openRequest.onsuccess = function() {
+ var db = openRequest.result;
+ try {
+ var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+ } catch(e) {
+ onerror(e);
+ return;
+ }
+ var files = transaction.objectStore(FS.DB_STORE_NAME);
+ var ok = 0, fail = 0, total = paths.length;
+ function finish() {
+ if (fail == 0) onload(); else onerror();
+ }
+ paths.forEach(function(path) {
+ var getRequest = files.get(path);
+ getRequest.onsuccess = function() {
+ if (FS.analyzePath(path).exists) {
+ FS.unlink(path);
+ }
+ FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+ ok++;
+ if (ok + fail == total) finish();
+ };
+ getRequest.onerror = function() { fail++; if (ok + fail == total) finish() };
+ });
+ transaction.onerror = onerror;
+ };
+ openRequest.onerror = onerror;
+ },
+
//
// general
//
diff --git a/tests/file_db.cpp b/tests/file_db.cpp
new file mode 100644
index 00000000..ebb3bb30
--- /dev/null
+++ b/tests/file_db.cpp
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <emscripten.h>
+
+void later(void *) {}
+
+int main() {
+#if FIRST
+ FILE *f = fopen("waka.txt", "w");
+ fputc('a', f);
+ fputc('z', f);
+ fclose(f);
+
+ EM_ASM(
+ FS.saveFilesToDB(['waka.txt', 'moar.txt'], function() {
+ Module.print('save ok');
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'http://localhost:8888/report_result?1');
+ xhr.send();
+ setTimeout(function() { window.close() }, 1000);
+ }, function(e) {
+ abort('saving should succeed ' + e);
+ });
+ );
+#else
+ EM_ASM(
+ FS.loadFilesFromDB(['waka.txt', 'moar.txt'], function() {
+ function stringy(arr) {
+ return Array.prototype.map.call(arr, function(x) { return String.fromCharCode(x) }).join('');
+ }
+ assert(stringy(FS.analyzePath('waka.txt').object.contents) == 'az');
+ var secret = stringy(FS.analyzePath('moar.txt').object.contents);
+ Module.print('load: ' + secret);
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'http://localhost:8888/report_result?' + secret);
+ xhr.send();
+ setTimeout(function() { window.close() }, 1000);
+ }, function() {
+ abort('loading should succeed');
+ });
+ );
+#endif
+
+ emscripten_async_call(later, NULL, 100); // keep runtime alive
+
+ return 0;
+}
+
diff --git a/tests/test_browser.py b/tests/test_browser.py
index 1c9cbfad..32b29966 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -794,6 +794,17 @@ If manually bisecting:
def test_glut_touchevents(self):
self.btest('glut_touchevents.c', '1')
+ def test_file_db(self):
+ secret = str(time.time())
+ open('moar.txt', 'w').write(secret)
+ self.btest('file_db.cpp', '1', args=['--preload-file', 'moar.txt', '-DFIRST'])
+ shutil.copyfile('test.html', 'first.html')
+ self.btest('file_db.cpp', secret)
+ shutil.copyfile('test.html', 'second.html')
+ open('moar.txt', 'w').write('aliantha')
+ self.btest('file_db.cpp', secret, args=['--preload-file', 'moar.txt']) # even with a file there, we load over it
+ shutil.move('test.html', 'third.html')
+
def test_sdl_pumpevents(self):
# key events should be detected using SDL_PumpEvents
open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''