| 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, | |
| }); | |
| } | |
| }; |