diff options
Diffstat (limited to 'platform/javascript/native')
-rw-r--r-- | platform/javascript/native/http_request.js | 146 | ||||
-rw-r--r-- | platform/javascript/native/id_handler.js | 63 | ||||
-rw-r--r-- | platform/javascript/native/utils.js | 204 |
3 files changed, 413 insertions, 0 deletions
diff --git a/platform/javascript/native/http_request.js b/platform/javascript/native/http_request.js new file mode 100644 index 0000000000..f621689f9d --- /dev/null +++ b/platform/javascript/native/http_request.js @@ -0,0 +1,146 @@ +/*************************************************************************/ +/* http_request.js */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +var GodotHTTPRequest = { + + $GodotHTTPRequest: { + + requests: [], + + getUnusedRequestId: function() { + var idMax = GodotHTTPRequest.requests.length; + for (var potentialId = 0; potentialId < idMax; ++potentialId) { + if (GodotHTTPRequest.requests[potentialId] instanceof XMLHttpRequest) { + continue; + } + return potentialId; + } + GodotHTTPRequest.requests.push(null) + return idMax; + }, + + setupRequest: function(xhr) { + xhr.responseType = 'arraybuffer'; + }, + }, + + godot_xhr_new: function() { + var newId = GodotHTTPRequest.getUnusedRequestId(); + GodotHTTPRequest.requests[newId] = new XMLHttpRequest; + GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[newId]); + return newId; + }, + + godot_xhr_reset: function(xhrId) { + GodotHTTPRequest.requests[xhrId] = new XMLHttpRequest; + GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[xhrId]); + }, + + godot_xhr_free: function(xhrId) { + GodotHTTPRequest.requests[xhrId].abort(); + GodotHTTPRequest.requests[xhrId] = null; + }, + + godot_xhr_open: function(xhrId, method, url, user, password) { + user = user > 0 ? UTF8ToString(user) : null; + password = password > 0 ? UTF8ToString(password) : null; + GodotHTTPRequest.requests[xhrId].open(UTF8ToString(method), UTF8ToString(url), true, user, password); + }, + + godot_xhr_set_request_header: function(xhrId, header, value) { + GodotHTTPRequest.requests[xhrId].setRequestHeader(UTF8ToString(header), UTF8ToString(value)); + }, + + godot_xhr_send_null: function(xhrId) { + GodotHTTPRequest.requests[xhrId].send(); + }, + + godot_xhr_send_string: function(xhrId, strPtr) { + if (!strPtr) { + err("Failed to send string per XHR: null pointer"); + return; + } + GodotHTTPRequest.requests[xhrId].send(UTF8ToString(strPtr)); + }, + + godot_xhr_send_data: function(xhrId, ptr, len) { + if (!ptr) { + err("Failed to send data per XHR: null pointer"); + return; + } + if (len < 0) { + err("Failed to send data per XHR: buffer length less than 0"); + return; + } + GodotHTTPRequest.requests[xhrId].send(HEAPU8.subarray(ptr, ptr + len)); + }, + + godot_xhr_abort: function(xhrId) { + GodotHTTPRequest.requests[xhrId].abort(); + }, + + godot_xhr_get_status: function(xhrId) { + return GodotHTTPRequest.requests[xhrId].status; + }, + + godot_xhr_get_ready_state: function(xhrId) { + return GodotHTTPRequest.requests[xhrId].readyState; + }, + + godot_xhr_get_response_headers_length: function(xhrId) { + var headers = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders(); + return headers === null ? 0 : lengthBytesUTF8(headers); + }, + + godot_xhr_get_response_headers: function(xhrId, dst, len) { + var str = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders(); + if (str === null) + return; + var buf = new Uint8Array(len + 1); + stringToUTF8Array(str, buf, 0, buf.length); + buf = buf.subarray(0, -1); + HEAPU8.set(buf, dst); + }, + + godot_xhr_get_response_length: function(xhrId) { + var body = GodotHTTPRequest.requests[xhrId].response; + return body === null ? 0 : body.byteLength; + }, + + godot_xhr_get_response: function(xhrId, dst, len) { + var buf = GodotHTTPRequest.requests[xhrId].response; + if (buf === null) + return; + buf = new Uint8Array(buf).subarray(0, len); + HEAPU8.set(buf, dst); + }, +}; + +autoAddDeps(GodotHTTPRequest, "$GodotHTTPRequest"); +mergeInto(LibraryManager.library, GodotHTTPRequest); diff --git a/platform/javascript/native/id_handler.js b/platform/javascript/native/id_handler.js new file mode 100644 index 0000000000..67d29075b8 --- /dev/null +++ b/platform/javascript/native/id_handler.js @@ -0,0 +1,63 @@ +/*************************************************************************/ +/* id_handler.js */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +var IDHandler = /** @constructor */ function() { + + var ids = {}; + var size = 0; + + this.has = function(id) { + return ids.hasOwnProperty(id); + } + + this.add = function(obj) { + size += 1; + var id = crypto.getRandomValues(new Int32Array(32))[0]; + ids[id] = obj; + return id; + } + + this.get = function(id) { + return ids[id]; + } + + this.remove = function(id) { + size -= 1; + delete ids[id]; + } + + this.size = function() { + return size; + } + + this.ids = ids; +}; + +Module.IDHandler = new IDHandler; diff --git a/platform/javascript/native/utils.js b/platform/javascript/native/utils.js new file mode 100644 index 0000000000..95585d26ae --- /dev/null +++ b/platform/javascript/native/utils.js @@ -0,0 +1,204 @@ +/*************************************************************************/ +/* utils.js */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +Module['copyToFS'] = function(path, buffer) { + var p = path.lastIndexOf("/"); + var dir = "/"; + if (p > 0) { + dir = path.slice(0, path.lastIndexOf("/")); + } + try { + FS.stat(dir); + } catch (e) { + if (e.errno !== ERRNO_CODES.ENOENT) { // 'ENOENT', see https://github.com/emscripten-core/emscripten/blob/master/system/lib/libc/musl/arch/emscripten/bits/errno.h + throw e; + } + FS.mkdirTree(dir); + } + // With memory growth, canOwn should be false. + FS.writeFile(path, new Uint8Array(buffer), {'flags': 'wx+'}); +} + +Module.drop_handler = (function() { + var upload = []; + var uploadPromises = []; + var uploadCallback = null; + + function readFilePromise(entry, path) { + return new Promise(function(resolve, reject) { + entry.file(function(file) { + var reader = new FileReader(); + reader.onload = function() { + var f = { + "path": file.relativePath || file.webkitRelativePath, + "name": file.name, + "type": file.type, + "size": file.size, + "data": reader.result + }; + if (!f['path']) + f['path'] = f['name']; + upload.push(f); + resolve() + }; + reader.onerror = function() { + console.log("Error reading file"); + reject(); + } + + reader.readAsArrayBuffer(file); + + }, function(err) { + console.log("Error!"); + reject(); + }); + }); + } + + function readDirectoryPromise(entry) { + return new Promise(function(resolve, reject) { + var reader = entry.createReader(); + reader.readEntries(function(entries) { + for (var i = 0; i < entries.length; i++) { + var ent = entries[i]; + if (ent.isDirectory) { + uploadPromises.push(readDirectoryPromise(ent)); + } else if (ent.isFile) { + uploadPromises.push(readFilePromise(ent)); + } + } + resolve(); + }); + }); + } + + function processUploadsPromises(resolve, reject) { + if (uploadPromises.length == 0) { + resolve(); + return; + } + uploadPromises.pop().then(function() { + setTimeout(function() { + processUploadsPromises(resolve, reject); + //processUploadsPromises.bind(null, resolve, reject) + }, 0); + }); + } + + function dropFiles(files) { + var args = files || []; + var argc = args.length; + var argv = stackAlloc((argc + 1) * 4); + for (var i = 0; i < argc; i++) { + HEAP32[(argv >> 2) + i] = allocateUTF8OnStack(args[i]); + } + HEAP32[(argv >> 2) + argc] = 0; + // Defined in display_server_javascript.cpp + ccall('_drop_files_callback', 'void', ['number', 'number'], [argv, argc]); + } + + return function(ev) { + ev.preventDefault(); + if (ev.dataTransfer.items) { + // Use DataTransferItemList interface to access the file(s) + for (var i = 0; i < ev.dataTransfer.items.length; i++) { + const item = ev.dataTransfer.items[i]; + var entry = null; + if ("getAsEntry" in item) { + entry = item.getAsEntry(); + } else if ("webkitGetAsEntry" in item) { + entry = item.webkitGetAsEntry(); + } + if (!entry) { + console.error("File upload not supported"); + } else if (entry.isDirectory) { + uploadPromises.push(readDirectoryPromise(entry)); + } else if (entry.isFile) { + uploadPromises.push(readFilePromise(entry)); + } else { + console.error("Unrecognized entry...", entry); + } + } + } else { + console.error("File upload not supported"); + } + uploadCallback = new Promise(processUploadsPromises).then(function() { + const DROP = "/tmp/drop-" + parseInt(Math.random() * Math.pow(2, 31)) + "/"; + var drops = []; + var files = []; + upload.forEach((elem) => { + var path = elem['path']; + Module['copyToFS'](DROP + path, elem['data']); + var idx = path.indexOf("/"); + if (idx == -1) { + // Root file + drops.push(DROP + path); + } else { + // Subdir + var sub = path.substr(0, idx); + idx = sub.indexOf("/"); + if (idx < 0 && drops.indexOf(DROP + sub) == -1) { + drops.push(DROP + sub); + } + } + files.push(DROP + path); + }); + uploadPromises = []; + upload = []; + dropFiles(drops); + var dirs = [DROP.substr(0, DROP.length -1)]; + files.forEach(function (file) { + FS.unlink(file); + var dir = file.replace(DROP, ""); + var idx = dir.lastIndexOf("/"); + while (idx > 0) { + dir = dir.substr(0, idx); + if (dirs.indexOf(DROP + dir) == -1) { + dirs.push(DROP + dir); + } + idx = dir.lastIndexOf("/"); + } + }); + // Remove dirs. + dirs = dirs.sort(function(a, b) { + var al = (a.match(/\//g) || []).length; + var bl = (b.match(/\//g) || []).length; + if (al > bl) + return -1; + else if (al < bl) + return 1; + return 0; + }); + dirs.forEach(function(dir) { + FS.rmdir(dir); + }); + }); + } +})(); |