UNPKG

@devicescript/vm

Version:
424 lines 13.4 kB
// devs_timeout === undefined - program is not running // devs_timeout === null - the C code is executing, program running // devs_timeout is number - we're waiting for timeout, program running var devs_timeout = undefined; function copyToHeap(buf, fn) { const ptr = Module._malloc(buf.length); Module.HEAPU8.set(buf, ptr); const r = fn(ptr); Module._free(ptr); return r; } function bufferConcat(a, b) { const r = new Uint8Array(a.length + b.length); r.set(a, 0); r.set(b, a.length); return r; } export var Exts; (function (Exts) { /** * Debug output and stack traces are sent here. */ Exts.dmesg = (s) => console.debug(" " + s); /** * Logging function */ Exts.log = console.log; /** * Error logging function */ Exts.error = console.error; /** * Callback to invoke when a packet needs to be handled by the virtual machine * TODO: frame or packet? * @param pkt a Jacdac frame */ function handlePacket(pkt) { if (devs_timeout) { try { copyToHeap(pkt, Module._jd_em_frame_received); } catch (_a) { } clearDevsTimeout(); process(); } } Exts.handlePacket = handlePacket; /** * Starts a packet transport over a TCP socket in a node.js application * @param require module resolution function, requires "net" package * @param host socket url host * @param port socket port */ function setupNodeTcpSocketTransport(require, host, port) { return new Promise((resolve, reject) => { const net = require("net"); let sock = null; const send = (data) => { let buf; if (data.length >= 0xff) { buf = new Uint8Array(3 + data.length); buf[0] = 0xff; buf[1] = data.length & 0xff; buf[2] = data.length >> 8; buf.set(data, 3); } else { buf = new Uint8Array(1 + data.length); buf[0] = data.length; buf.set(data, 1); } if (sock) sock.write(buf); }; const disconnect = (err) => { Module.log("disconnect", err === null || err === void 0 ? void 0 : err.message); if (sock) try { sock.end(); } catch (_a) { } finally { sock = undefined; } if (resolve) { resolve = null; reject(new Error(`can't connect to ${host}:${port}`)); } }; const close = () => disconnect(undefined); Module["sendPacket"] = send; sock = net.createConnection(port, host, () => { Module.log(`connected to ${host}:${port}`); const f = resolve; if (f) { resolve = null; reject = null; f({ close }); } }); sock.on("error", disconnect); sock.on("end", disconnect); sock.setNoDelay(); let acc = null; sock.on("data", (buf) => { if (acc) { buf = bufferConcat(acc, buf); acc = null; } else { buf = new Uint8Array(buf); } while (buf) { const endp = buf[0] + 1; if (buf.length >= endp) { const pkt = buf.slice(1, endp); if (buf.length > endp) buf = buf.slice(endp); else buf = null; Module.handlePacket(pkt); } else { acc = buf; buf = null; } } }); }); } Exts.setupNodeTcpSocketTransport = setupNodeTcpSocketTransport; /** * Starts a packet transport over a WebSocket using arraybuffer binary type. * @param url socket url * @param port socket port */ function setupWebsocketTransport(url, protocols) { return new Promise((resolve, reject) => { let sock = new WebSocket(url, protocols); if (sock.binaryType != "arraybuffer") sock.binaryType = "arraybuffer"; const send = (data) => { if (sock && sock.readyState == WebSocket.OPEN) { sock.send(data); return 0; } else { return -1; } }; const disconnect = (err) => { Module.log("disconnect", err === null || err === void 0 ? void 0 : err.message); if (sock) try { sock.close(); } catch (_a) { } finally { sock = undefined; } if (resolve) { resolve = null; reject(new Error(`can't connect to ${url}; ${err === null || err === void 0 ? void 0 : err.message}`)); } }; const close = () => disconnect(undefined); Module["sendPacket"] = send; sock.onopen = () => { Module.log(`connected to ${url}`); const f = resolve; if (f) { resolve = null; reject = null; f({ close }); } }; sock.onerror = disconnect; sock.onclose = disconnect; sock.onmessage = ev => { const data = ev.data; if (typeof data == "string") { Module.error("got string msg"); return; } else { const pkt = new Uint8Array(ev.data); Module.handlePacket(pkt); } }; }); } Exts.setupWebsocketTransport = setupWebsocketTransport; /** * Utility that converts a base64-encoded buffer into a Uint8Array * TODO: nobody is using this? * @param s * @returns */ function b64ToBin(s) { s = atob(s); const r = new Uint8Array(s.length); for (let i = 0; i < s.length; ++i) r[i] = s.charCodeAt(i); return r; } Exts.b64ToBin = b64ToBin; /** * Deploys a DeviceScript bytecode to the virtual machine * @param binary * @returns error code, 0 if deployment is successful */ function devsDeploy(binary) { return copyToHeap(binary, ptr => Module._jd_em_devs_deploy(ptr, binary.length)); } Exts.devsDeploy = devsDeploy; /** * Verifies the format and version of the bytecode * @param binary DeviceScript bytecode * @returns error code, 0 if verification is successful */ function devsVerify(binary) { return copyToHeap(binary, ptr => Module._jd_em_devs_verify(ptr, binary.length)); } Exts.devsVerify = devsVerify; /** * Deploys to the first virtual machine on Jacdac stack (experimental) * @internal * @alpha * @param binary * @returns error code, 0 if deployment is successful */ function devsClientDeploy(binary) { // this will call exit(0) when done const ptr = Module._malloc(binary.length); Module.HEAPU8.set(binary, ptr); return Module._jd_em_devs_client_deploy(ptr, binary.length); } Exts.devsClientDeploy = devsClientDeploy; /** * Initalises the virtual machine data structure. */ function devsInit() { Module._jd_em_init(); } Exts.devsInit = devsInit; /** * Enables/disables GC stress testing. */ function devsGcStress(en) { Module._jd_em_devs_enable_gc_stress(en ? 1 : 0); } Exts.devsGcStress = devsGcStress; /** * Clear settings. */ function devsClearFlash() { if (Module.flashSave) Module.flashSave(new Uint8Array([0, 0, 0, 0])); } Exts.devsClearFlash = devsClearFlash; function process() { devs_timeout = null; try { const us = Module._jd_em_process(); devs_timeout = setTimeout(process, us / 1000); } catch (e) { Module.error(e); devsStop(); } } function clearDevsTimeout() { if (devs_timeout) clearInterval(devs_timeout); devs_timeout = undefined; } /** * Initializes and start the virtual machine (calls init). */ function devsStart() { if (devs_timeout) return; Module.devsInit(); devs_timeout = setTimeout(process, 10); } Exts.devsStart = devsStart; /** * Stops the virtual machine */ function devsStop() { clearDevsTimeout(); } Exts.devsStop = devsStop; /** * Indicates if the virtual machine is running * @returns true if the virtual machine is started. */ function devsIsRunning() { return devs_timeout !== undefined; } Exts.devsIsRunning = devsIsRunning; /** * Specifices the virtual macine device id. * @remarks * * Must be called before `devsStart`. * * @param id0 a hex-encoded device id string or the first 32bit of the device id * @param id1 the second 32 bits of the device id, undefined if id0 is a string */ function devsSetDeviceId(id0, id1) { if (devsIsRunning()) throw new Error("cannot change deviceid while running"); Module.devsInit(); if (typeof id0 == "string") { if (id1 !== undefined) throw new Error("invalid arguments"); const s = allocateUTF8(id0); Module._jd_em_set_device_id_string(s); Module._free(s); } else if (typeof id0 == "number" && typeof id1 == "number") { Module._jd_em_set_device_id_2x_i32(id0, id1); } else { throw new Error("invalid arguments"); } } Exts.devsSetDeviceId = devsSetDeviceId; let currSock; function sockClose() { if (!currSock) return -10; currSock.end(); currSock = null; return 0; } Exts.sockClose = sockClose; function sockWrite(data, len) { if (!currSock) return -10; const buf = Module.HEAPU8.slice(data, data + len); currSock.write(buf); return 0; } Exts.sockWrite = sockWrite; function sockIsAvailable() { try { require("node:tls"); return true; } catch (_a) { return false; } } Exts.sockIsAvailable = sockIsAvailable; function sockOpen(hostptr, port) { const host = UTF8ToString(hostptr, 256); const JD_CONN_EV_OPEN = 0x01; const JD_CONN_EV_CLOSE = 0x02; const JD_CONN_EV_ERROR = 0x03; const JD_CONN_EV_MESSAGE = 0x04; const isTLS = port < 0; if (isTLS) port = -port; const name = `${isTLS ? "tls" : "tcp"}://${host}:${port}`; currSock === null || currSock === void 0 ? void 0 : currSock.end(); currSock = null; const sock = isTLS ? require("tls").connect({ host, port, }) : require("net").createConnection({ host, port }); currSock = sock; currSock.once("connect", () => { if (sock === currSock) cb(JD_CONN_EV_OPEN); }); currSock.on("data", (buf) => { if (sock === currSock) cb(JD_CONN_EV_MESSAGE, buf); }); currSock.on("error", (err) => { if (sock === currSock) { cb(JD_CONN_EV_ERROR, `${name}: ${err.message}`); currSock = null; } }); currSock.on("close", (hadError) => { if (sock === currSock) { cb(JD_CONN_EV_CLOSE); currSock = null; } }); function cb(tp, arg) { let len = arg ? arg.length : 0; let ptr = 0; if (typeof arg === "string") { len = lengthBytesUTF8(arg); ptr = allocateUTF8(arg); } else if (arg) { ptr = Module._malloc(len); Module.HEAPU8.set(arg, ptr); } Module._jd_em_tcpsock_on_event(tp, ptr, len); if (ptr) Module._free(ptr); } } Exts.sockOpen = sockOpen; })(Exts || (Exts = {})); for (const kn of Object.keys(Exts)) { ; Module[kn] = Exts[kn]; } function factory() { return null; } export default factory; //# sourceMappingURL=wasmpre.js.map