接续L4-TOOL-DB浏览器Provider协议
结论:浏览器 Worker 已支持可插拔 Python runtime provider 的 line I/O,缺真实 Python/WASM runtime 时仍保持阻塞不解锁。
This commit is contained in:
@@ -577,7 +577,9 @@ private module paths:
|
||||
boundary. The bundled worker reports
|
||||
`blocked_browser_python_wasm_runtime_missing` until a real Python/WASM runtime
|
||||
is installed; the Worker shell alone must not mark `DB_PROGRAM` execution
|
||||
ready.
|
||||
ready. The Worker supports a provider protocol (`start`, `writeLine`,
|
||||
`readLine`, `close`) so a future Python/WASM runtime can provide line-based
|
||||
`DB_PROGRAM` I/O without changing `ToolDbProcessPort`.
|
||||
- `createLinuxCncToolDbNodeRuntimeAdapter()` in
|
||||
`runtime/sdk/src/tool-db-node-runtime-adapter.js` for Node/native verification
|
||||
of the real LinuxCNC `DB_PROGRAM` child process. This adapter is intentionally
|
||||
|
||||
@@ -96,7 +96,14 @@ export function createLinuxCncToolDbBrowserWorkerAdapter({
|
||||
return result.line;
|
||||
},
|
||||
|
||||
close() {
|
||||
async close() {
|
||||
if (worker) {
|
||||
try {
|
||||
await request("close");
|
||||
} catch {
|
||||
// The worker may be blocked or already gone; termination below is authoritative.
|
||||
}
|
||||
}
|
||||
rejectPending(new Error("Tool DB browser worker closed."));
|
||||
worker?.terminate();
|
||||
worker = null;
|
||||
|
||||
@@ -15,12 +15,21 @@ function pythonRuntimeAvailable() {
|
||||
return typeof self.loadPyodide === "function" || Boolean(self.pyodide?.runPythonAsync);
|
||||
}
|
||||
|
||||
function getRuntimeProvider() {
|
||||
return self.linuxCncToolDbPythonRuntimeProvider ?? null;
|
||||
}
|
||||
|
||||
self.addEventListener("message", async (event) => {
|
||||
const message = event.data ?? {};
|
||||
const { id, type } = message;
|
||||
const { id, type, line } = message;
|
||||
try {
|
||||
if (type === "start") {
|
||||
const ready = pythonRuntimeAvailable();
|
||||
const provider = getRuntimeProvider();
|
||||
const providerReady = Boolean(provider?.start && provider?.writeLine && provider?.readLine);
|
||||
const ready = providerReady || pythonRuntimeAvailable();
|
||||
if (providerReady) {
|
||||
await provider.start(message);
|
||||
}
|
||||
postReply(id, type, {
|
||||
runtimeMode: "browser-python-wasm-worker",
|
||||
runtimeExecutionReady: ready,
|
||||
@@ -32,6 +41,25 @@ self.addEventListener("message", async (event) => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
const provider = getRuntimeProvider();
|
||||
if (type === "writeLine" && provider?.writeLine) {
|
||||
await provider.writeLine(line);
|
||||
postReply(id, type, { executionEnabled: false, promotionAllowed: false });
|
||||
return;
|
||||
}
|
||||
if (type === "readLine" && provider?.readLine) {
|
||||
postReply(id, type, {
|
||||
line: await provider.readLine(),
|
||||
executionEnabled: false,
|
||||
promotionAllowed: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (type === "close" && provider?.close) {
|
||||
await provider.close();
|
||||
postReply(id, type, { executionEnabled: false, promotionAllowed: false });
|
||||
return;
|
||||
}
|
||||
throw new Error("blocked_browser_python_wasm_runtime_missing");
|
||||
} catch (error) {
|
||||
postError(id, type, error);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
self.linuxCncToolDbPythonRuntimeProvider = {
|
||||
lines: [
|
||||
"v2.1",
|
||||
"T10 P110 D0.10 Z0.10",
|
||||
"FINI (get_cmd)",
|
||||
"FINI (update recvd) t11 p111 d0.33 z0.11",
|
||||
"FINI (update recvd) t14 p0",
|
||||
"FINI (update recvd) t0 p0",
|
||||
],
|
||||
|
||||
async start() {},
|
||||
|
||||
async writeLine() {},
|
||||
|
||||
async readLine() {
|
||||
return this.lines.shift();
|
||||
},
|
||||
|
||||
async close() {},
|
||||
};
|
||||
|
||||
await import("../../runtime/workers/tool-db-python-worker.js");
|
||||
@@ -85,6 +85,23 @@
|
||||
assertEqual(workerPlanResult.promotionAllowed, false, "worker promotion guard");
|
||||
await workerPort.close();
|
||||
|
||||
const fakeRuntimeAdapter = createLinuxCncToolDbBrowserWorkerAdapter({
|
||||
workerUrl: new URL("./tool_db_fake_python_runtime_worker.js", import.meta.url),
|
||||
});
|
||||
const fakeRuntimePort = createLinuxCncToolDbProcessPort({
|
||||
dbProgramPath: "./db_nonran.py",
|
||||
runtimeMode: fakeRuntimeAdapter.runtimeMode,
|
||||
runtimeAdapter: fakeRuntimeAdapter,
|
||||
});
|
||||
const fakeRuntimeStart = await fakeRuntimePort.start();
|
||||
assertEqual(fakeRuntimeStart.runtimeExecutionReady, true, "fake provider runtime readiness");
|
||||
assertEqual(fakeRuntimeStart.status, "browser_python_wasm_runtime_ready", "fake provider runtime status");
|
||||
const fakeRuntimePlan = await fakeRuntimePort.runTransactionPlan();
|
||||
assertEqual(fakeRuntimePlan.status, "runtime_adapter_transaction_plan_executed", "fake provider plan");
|
||||
assertEqual(fakeRuntimePlan.promotionAllowed, false, "fake provider promotion guard");
|
||||
assertEqual(validateToolDbTranscript(fakeRuntimePort.exportTranscript()).ready, true, "fake provider transcript");
|
||||
await fakeRuntimePort.close();
|
||||
|
||||
const transcript = [
|
||||
{ direction: "read", line: "v2.1" },
|
||||
{ direction: "write", line: "g" },
|
||||
|
||||
@@ -80,6 +80,66 @@ class FakeBlockedWorker {
|
||||
terminate() {}
|
||||
}
|
||||
|
||||
class FakeReadyWorker {
|
||||
constructor() {
|
||||
this.listeners = new Map();
|
||||
this.lines = [
|
||||
"v2.1",
|
||||
"T10 P110 D0.10 Z0.10",
|
||||
"FINI (get_cmd)",
|
||||
"FINI (update recvd) t11 p111 d0.33 z0.11",
|
||||
"FINI (update recvd) t14 p0",
|
||||
"FINI (update recvd) t0 p0",
|
||||
];
|
||||
}
|
||||
|
||||
addEventListener(type, listener) {
|
||||
this.listeners.set(type, listener);
|
||||
}
|
||||
|
||||
postMessage(message) {
|
||||
queueMicrotask(() => {
|
||||
if (message.type === "start") {
|
||||
this.reply(message, {
|
||||
runtimeExecutionReady: true,
|
||||
status: "browser_python_wasm_runtime_ready",
|
||||
executionEnabled: false,
|
||||
promotionAllowed: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (message.type === "writeLine") {
|
||||
this.reply(message, { executionEnabled: false, promotionAllowed: false });
|
||||
return;
|
||||
}
|
||||
if (message.type === "readLine") {
|
||||
this.reply(message, {
|
||||
line: this.lines.shift(),
|
||||
executionEnabled: false,
|
||||
promotionAllowed: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (message.type === "close") {
|
||||
this.reply(message, { executionEnabled: false, promotionAllowed: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reply(message, payload) {
|
||||
this.listeners.get("message")?.({
|
||||
data: {
|
||||
id: message.id,
|
||||
type: message.type,
|
||||
ok: true,
|
||||
...payload,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
terminate() {}
|
||||
}
|
||||
|
||||
const browserWorkerAdapter = createLinuxCncToolDbBrowserWorkerAdapter({
|
||||
workerUrl: "./tool-db-python-worker.js",
|
||||
workerFactory: () => new FakeBlockedWorker(),
|
||||
@@ -99,6 +159,25 @@ assert.equal(browserWorkerBlockedPlan.runtimeExecutionReady, false);
|
||||
assert.equal(browserWorkerBlockedPlan.promotionAllowed, false);
|
||||
await browserWorkerPort.close();
|
||||
|
||||
const readyWorkerAdapter = createLinuxCncToolDbBrowserWorkerAdapter({
|
||||
workerUrl: "./tool-db-python-worker.js",
|
||||
workerFactory: () => new FakeReadyWorker(),
|
||||
});
|
||||
const readyWorkerPort = createLinuxCncToolDbProcessPort({
|
||||
dbProgramPath: "./db_nonran.py",
|
||||
runtimeMode: readyWorkerAdapter.runtimeMode,
|
||||
runtimeAdapter: readyWorkerAdapter,
|
||||
});
|
||||
const readyWorkerStart = await readyWorkerPort.start();
|
||||
assert.equal(readyWorkerStart.runtimeExecutionReady, true);
|
||||
assert.equal(readyWorkerStart.status, "browser_python_wasm_runtime_ready");
|
||||
const readyWorkerPlan = await readyWorkerPort.runTransactionPlan();
|
||||
assert.equal(readyWorkerPlan.status, "runtime_adapter_transaction_plan_executed");
|
||||
assert.equal(readyWorkerPlan.runtimeExecutionReady, true);
|
||||
assert.equal(readyWorkerPlan.promotionAllowed, false);
|
||||
assert.equal(validateToolDbTranscript(readyWorkerPort.exportTranscript()).ready, true);
|
||||
await readyWorkerPort.close();
|
||||
|
||||
const transcript = [
|
||||
{ direction: "read", line: "v2.1" },
|
||||
{ direction: "write", line: "g" },
|
||||
|
||||
Reference in New Issue
Block a user