storage.cpp (2853B)
1 #include "storage.h" 2 3 #include "emscripten.h" 4 #include <filesystem> 5 #include <fstream> 6 7 EM_JS(int, inbrowser, (), { return typeof window !== 'undefined'; }); 8 EM_JS(int, inworker, (), { return typeof WorkerGlobalScope !== 'undefined' && 9 self instanceof WorkerGlobalScope; }); 10 11 std::string getprefix() { 12 return inbrowser() || inworker() ? "/tables/" : "./tables/"; 13 } 14 15 EM_ASYNC_JS(int, loadfs, (), { 16 const inBrowser = typeof window !== 'undefined'; 17 const inWorker = typeof WorkerGlobalScope !== 'undefined' && 18 self instanceof WorkerGlobalScope; 19 console.assert(inBrowser || inWorker, "Non-browsers not supported"); 20 21 const dir = '/tables'; 22 23 if (!FS.analyzePath(dir).exists) 24 FS.mkdir(dir); 25 26 if (FS.analyzePath(dir).object.mount.mountpoint != dir) { 27 FS.mount(IDBFS, { autoPersist: true }, dir); 28 29 await new Promise((resolve, reject) => { 30 FS.syncfs(true, function (err) { 31 if (err) 32 reject(err); 33 else 34 resolve(true); 35 }); 36 }); 37 } 38 }); 39 40 EM_ASYNC_JS(int, download_and_store, (const char *key, const char *url), { 41 const inBrowser = typeof window !== 'undefined'; 42 const inWorker = typeof WorkerGlobalScope !== 'undefined' && 43 self instanceof WorkerGlobalScope; 44 console.assert(inBrowser || inWorker, "Non-browsers not supported"); 45 46 // This is a workaround related to usign WASM64 47 // JavaScript's UTF8ToString expects a pointer argument, which for JS is 48 // of type "number", but WASM64 is passing a BigInt. See also: 49 // https://github.com/emscripten-core/emscripten/issues/21541 50 // (but I could not make the suggested solution work in this case). 51 // TODO: check if there is a better workaround. 52 const non64_url = Number(url); 53 const non64_key = Number(key); 54 url = UTF8ToString(non64_url); 55 key = UTF8ToString(non64_key); 56 let response = await fetch(url); 57 if (!response.ok) { 58 console.log("Error downloading data for " + key); 59 console.log("" + response.status + ": " + response.statusText); 60 return 0; 61 } 62 63 let data = await response.bytes(); 64 var stream = FS.open("/tables/" + key, "w+"); 65 FS.write(stream, data, 0, data.length, 0); 66 FS.close(stream); 67 console.log("Data for " + key + " stored (" + data.length + " bytes)"); 68 return 1; 69 }); 70 71 bool storage::read(std::string key, size_t data_size, char *data) 72 { 73 loadfs(); 74 75 std::filesystem::path path(getprefix() + key); 76 if (!std::filesystem::exists(path)) 77 return false; 78 79 std::ifstream ifs(path, std::ios::binary); 80 ifs.read(data, data_size); 81 ifs.close(); 82 83 return !ifs.fail(); 84 } 85 86 bool storage::write(std::string key, size_t data_size, const char *data) 87 { 88 loadfs(); 89 90 std::filesystem::path path(getprefix() + key); 91 92 std::ofstream ofs(path, std::ios::binary); 93 ofs.write(data, data_size); 94 ofs.close(); 95 96 return !ofs.fail(); 97 } 98 99 int storage::download(std::string key, std::string url) 100 { 101 loadfs(); 102 return download_and_store(key.c_str(), url.c_str()); 103 }