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 versionHex = Module.HEAPU32[Module._Py_Version/4].toString(16); const versionTuple = versionHex.padStart(8, "0").match(/.{1,2}/g).map((x) => parseInt(x, 16)); const [major, minor, ..._] = versionTuple; // 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 }) } }