import createEmscriptenModule from "./python.mjs"; class StdinBuffer { constructor() { this.sab = new SharedArrayBuffer(128 * Int32Array.BYTES_PER_ELEMENT); this.buffer = new Int32Array(this.sab); this.readIndex = 1; this.numberOfCharacters = 0; this.sentNull = true; } prompt() { this.readIndex = 1; Atomics.store(this.buffer, 0, -1); postMessage({ type: "stdin", buffer: this.sab, }); Atomics.wait(this.buffer, 0, -1); this.numberOfCharacters = this.buffer[0]; } stdin = () => { while (this.numberOfCharacters + 1 === this.readIndex) { if (!this.sentNull) { // Must return null once to indicate we're done for now. this.sentNull = true; return null; } this.sentNull = false; // Prompt will reset this.readIndex to 1 this.prompt(); } const char = this.buffer[this.readIndex]; this.readIndex += 1; return char; }; } const stdout = (charCode) => { if (charCode) { postMessage({ type: "stdout", stdout: charCode, }); } else { console.log(typeof charCode, charCode); } }; const stderr = (charCode) => { if (charCode) { postMessage({ type: "stderr", stderr: charCode, }); } else { console.log(typeof charCode, charCode); } }; const stdinBuffer = new StdinBuffer(); const emscriptenSettings = { noInitialRun: true, stdin: stdinBuffer.stdin, stdout: stdout, stderr: stderr, onRuntimeInitialized: () => { postMessage({ type: "ready", stdinBuffer: stdinBuffer.sab }); }, async preRun(Module) { const versionInt = Module.HEAPU32[Module._Py_Version >>> 2]; const major = (versionInt >>> 24) & 0xff; const minor = (versionInt >>> 16) & 0xff; // Prevent complaints about not finding exec-prefix by making a lib-dynload directory Module.FS.mkdirTree(`/lib/python${major}.${minor}/lib-dynload/`); Module.addRunDependency("install-stdlib"); const resp = await fetch(`python${major}.${minor}.zip`); const stdlibBuffer = await resp.arrayBuffer(); Module.FS.writeFile( `/lib/python${major}${minor}.zip`, new Uint8Array(stdlibBuffer), { canOwn: true }, ); Module.removeRunDependency("install-stdlib"); }, }; const modulePromise = createEmscriptenModule(emscriptenSettings); onmessage = async (event) => { if (event.data.type === "run") { const Module = await modulePromise; if (event.data.files) { for (const [filename, contents] of Object.entries(event.data.files)) { Module.FS.writeFile(filename, contents); } } const ret = Module.callMain(event.data.args); postMessage({ type: "finished", returnCode: ret, }); } };