Skip to content

Commit

Permalink
Introduce an ‘incremental-features’ flag for the Pyodide web worker
Browse files Browse the repository at this point in the history
Not all use cases will require support for standard input and stopping
execution so make it so the web worker can work without these features.
The developer must explicitly opt-in to this with ‘incremental-features’
to acknowledge the limitations of the web worker.
  • Loading branch information
tuzz committed Jan 24, 2024
1 parent 80a512f commit fd2c50e
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 12 deletions.
2 changes: 2 additions & 0 deletions pyodide/serviceworker.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ self.addEventListener("fetch", (event) => {

event.respondWith(
fetch(event.request).then(response => {
// if (!response.url.includes("/some/page/that/hosts/the/editor")) { return; }

const body = response.body;
const status = response.status;
const headers = new Headers(response.headers);
Expand Down
40 changes: 28 additions & 12 deletions pyodide/webworker.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
const supportsAllFeatures = typeof SharedArrayBuffer !== "undefined";

if (!supportsAllFeatures && name !== "incremental-features") {
console.warn([
"The code editor will not be able to capture standard input or stop execution because these HTTP headers are not set:",
" - Cross-Origin-Opener-Policy: same-origin",
" - Cross-Origin-Embedder-Policy: require-corp",
"",
"If your app can cope with or without these features, please initialize the web worker with { name: 'incremental-features' } to silence this warning.",
"You can then check for the presence of { stdinBuffer, interruptBuffer } in the handleLoaded message to check whether these features are supported.",
"",
"If you definitely need these features, either configure your server to respond with the HTTP headers above, or register a service worker.",
"Once the HTTP headers are set, the browser will block cross-domain resources so you will need to add 'crossorigin' to <script> and other tags.",
"You may wish to scope the HTTP headers to only those pages that host the code editor to make the browser restriction easier to deal with.",
"",
"Please refer to these code snippets for registering a service worker:",
" - https://github.com/RaspberryPiFoundation/python-execution-prototypes/blob/80a512f0942d326460b27c6ff7574887bd14a6c3/pyodide/index.html#L92-L98",
" - https://github.com/RaspberryPiFoundation/python-execution-prototypes/blob/80a512f0942d326460b27c6ff7574887bd14a6c3/pyodide/serviceworker.js",
].join("\n"));
}

import "https://cdn.jsdelivr.net/pyodide/v0.24.1/full/pyodide.js";
import * as pygal from "./packages/pygal.js";
import * as _internal_sense_hat from "./packages/_internal_sense_hat.js";
Expand Down Expand Up @@ -154,12 +175,14 @@ const reloadPyodideToClearState = async () => {

const pyodide = await pyodidePromise;

stdinBuffer ||= new Int32Array(new SharedArrayBuffer(1024 * 1024)); // 1 MiB
stdinBuffer[0] = 1; // Store the length of content in the buffer at index 0.
pyodide.setStdin({ isatty: true, read: readFromStdin });
if (supportsAllFeatures) {
stdinBuffer ||= new Int32Array(new SharedArrayBuffer(1024 * 1024)); // 1 MiB
stdinBuffer[0] = 1; // Store the length of content in the buffer at index 0.
pyodide.setStdin({ isatty: true, read: readFromStdin });

interruptBuffer ||= new Uint8Array(new SharedArrayBuffer(1));
pyodide.setInterruptBuffer(interruptBuffer);
interruptBuffer ||= new Uint8Array(new SharedArrayBuffer(1));
pyodide.setInterruptBuffer(interruptBuffer);
}

postMessage({ method: "handleLoaded", stdinBuffer, interruptBuffer });
};
Expand All @@ -181,13 +204,6 @@ const readFromStdin = (bufferToWrite) => {
return addedBytes.length;
};

if (typeof SharedArrayBuffer === "undefined") {
throw new Error(`Please set the following HTTP headers for webworker.js to support stdin and the stop button:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
`);
}

const parsePythonError = (error) => {
const type = error.type;
const [trace, content] = error.message.split(`${type}:`).map(s => s?.trim());
Expand Down

0 comments on commit fd2c50e

Please sign in to comment.