shifted pyodide to a worker thread, added hooks for external functions from python to javascript
parent
4904e2901c
commit
e16c94f273
110
index.html
110
index.html
|
|
@ -30,78 +30,48 @@
|
||||||
<div id="console"></div>
|
<div id="console"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
async function initializePyodide() {
|
const consoleElement = document.getElementById("console");
|
||||||
let pyodide = await loadPyodide({
|
let pyodideWorker = new Worker("pyodide-worker.js");
|
||||||
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.23.4/full/"
|
|
||||||
|
pyodideWorker.onmessage = (event) => {
|
||||||
|
switch (event.data.type) {
|
||||||
|
case "console":
|
||||||
|
logToConsole(event.data.data);
|
||||||
|
break;
|
||||||
|
case "error":
|
||||||
|
logToConsole(`<span style="color:red;">${event.data.message}</span>`);
|
||||||
|
break;
|
||||||
|
case "fire":
|
||||||
|
fire(); // Call the JavaScript fire() function
|
||||||
|
break;
|
||||||
|
case "turn":
|
||||||
|
turn(event.data.data); // Call the JavaScript turn(deg) function
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function logToConsole(text) {
|
||||||
|
console.log(text.replace("<b>", "").replace("</b>", ""));
|
||||||
|
consoleElement.innerHTML += text.replace(/\n/g, "<br>") + "<br>";
|
||||||
|
consoleElement.scrollTop = consoleElement.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ JavaScript functions to handle events
|
||||||
|
function fire() {
|
||||||
|
logToConsole("<b>🔥 Gun Fired! 🔥</b>");
|
||||||
|
}
|
||||||
|
|
||||||
|
function turn(deg) {
|
||||||
|
logToConsole(`<b>🔄 Turned ${deg} degrees</b>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send code to worker
|
||||||
|
document.getElementById("compile-button").addEventListener("click", () => {
|
||||||
|
const code = document.getElementById("python-code").value;
|
||||||
|
consoleElement.innerHTML = ""; // Clear console before running new code
|
||||||
|
pyodideWorker.postMessage({ code });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Redirect Python's stdout and stderr to the console area
|
|
||||||
pyodide.runPython(`
|
|
||||||
import sys
|
|
||||||
import asyncio
|
|
||||||
from js import document
|
|
||||||
|
|
||||||
class ConsoleOutput:
|
|
||||||
def write(self, text):
|
|
||||||
console = document.getElementById("console")
|
|
||||||
|
|
||||||
console.innerHTML += text.replace("\\n", "<br>") # Convert newlines to <br>
|
|
||||||
console.scrollTop = console.scrollHeight # Auto-scroll to bottom
|
|
||||||
|
|
||||||
def flush(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
sys.stdout = ConsoleOutput()
|
|
||||||
sys.stderr = ConsoleOutput()
|
|
||||||
`);
|
|
||||||
|
|
||||||
|
|
||||||
return pyodide;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function runPythonCode(pyodide, code) {
|
|
||||||
try {
|
|
||||||
// Clear the console before running new code
|
|
||||||
document.getElementById("console").textContent = "";
|
|
||||||
|
|
||||||
// Run the Python code asynchronously
|
|
||||||
console.log(code);
|
|
||||||
function addExtraLineWithIndent(inputString, additionalText = "") {
|
|
||||||
// Split the string into an array of lines
|
|
||||||
const lines = inputString.split('\n');
|
|
||||||
const result = lines.map(line => {
|
|
||||||
// Check if the line ends with a colon
|
|
||||||
if (line.trim().endsWith(":")) {
|
|
||||||
return line; // Leave it as is
|
|
||||||
}
|
|
||||||
// Extract leading whitespace (indentation) from the current line
|
|
||||||
const indentation = line.match(/^\s*/)[0];
|
|
||||||
// Add the original line and the new inserted line with indentation
|
|
||||||
return line + '\n' + indentation + additionalText;
|
|
||||||
}).join('\n'); // Combine the lines back into a single string
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const output = addExtraLineWithIndent(code, "await asyncio.sleep(0.01)");
|
|
||||||
console.log(output);
|
|
||||||
|
|
||||||
|
|
||||||
await pyodide.runPythonAsync(output);
|
|
||||||
} catch (err) {
|
|
||||||
// Display any errors in the console area
|
|
||||||
document.getElementById("console").textContent += `Error: ${err}\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", async () => {
|
|
||||||
let pyodide = await initializePyodide();
|
|
||||||
|
|
||||||
document.getElementById("compile-button").addEventListener("click", async () => {
|
|
||||||
let code = document.getElementById("python-code").value;
|
|
||||||
await runPythonCode(pyodide, code);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
importScripts("https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js");
|
||||||
|
|
||||||
|
async function initializePyodide() {
|
||||||
|
self.pyodide = await loadPyodide({
|
||||||
|
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.23.4/full/"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Expose a function to send messages from Python to JavaScript
|
||||||
|
self.pyodide.globals.set("send_to_main", (event, data) => {
|
||||||
|
self.postMessage({ type: event, data: data });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define the fire() and turn(deg) functions in Python
|
||||||
|
self.pyodide.runPython(`
|
||||||
|
import sys
|
||||||
|
import pyodide
|
||||||
|
|
||||||
|
def fire():
|
||||||
|
pyodide.ffi.to_js(send_to_main)("fire", None)
|
||||||
|
|
||||||
|
def turn(deg):
|
||||||
|
pyodide.ffi.to_js(send_to_main)("turn", deg)
|
||||||
|
|
||||||
|
class ConsoleOutput:
|
||||||
|
def write(self, text):
|
||||||
|
if text.strip(): # Avoid empty writes
|
||||||
|
pyodide.ffi.to_js(send_to_main)("console", text)
|
||||||
|
return None # Prevent 'undefined' from appearing
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
sys.stdout = ConsoleOutput()
|
||||||
|
sys.stderr = ConsoleOutput()
|
||||||
|
`);
|
||||||
|
|
||||||
|
self.postMessage({ type: "ready" }); // Notify main thread that Pyodide is ready
|
||||||
|
}
|
||||||
|
|
||||||
|
initializePyodide();
|
||||||
|
|
||||||
|
self.onmessage = async (event) => {
|
||||||
|
if (!self.pyodide) {
|
||||||
|
self.postMessage({ type: "error", message: "Pyodide not initialized yet." });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let result = await self.pyodide.runPythonAsync(event.data.code);
|
||||||
|
|
||||||
|
if (result !== undefined && result !== null && result !== "") {
|
||||||
|
self.postMessage({ type: "console", data: result });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
self.postMessage({ type: "error", message: error.toString() });
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue