结论:53 个 Python-remap inventory rows 已完成 row proof、browser proof 与 inventory baseline promotion,当前 inventory baseline 为 PASS=82 / SKIP=77 / unexpected_fail=0。
164 lines
4.8 KiB
JavaScript
164 lines
4.8 KiB
JavaScript
function requireWorkerUrl(value) {
|
|
if (typeof value === "string" && value.length > 0) {
|
|
return value;
|
|
}
|
|
if (value instanceof URL) {
|
|
return value;
|
|
}
|
|
throw new Error("workerUrl must be a non-empty string or URL.");
|
|
}
|
|
|
|
function makeRequestId() {
|
|
return `python-remap-worker-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
}
|
|
|
|
export function createLinuxCncPythonRemapBrowserWorkerAdapter({
|
|
workerUrl,
|
|
pythonRuntimeModuleUrl = null,
|
|
workerFactory = (url) => new Worker(url, { type: "module" }),
|
|
timeoutMs = 5000,
|
|
} = {}) {
|
|
const normalizedWorkerUrl = requireWorkerUrl(workerUrl);
|
|
const normalizedPythonRuntimeModuleUrl = pythonRuntimeModuleUrl ? requireWorkerUrl(pythonRuntimeModuleUrl) : null;
|
|
let worker = null;
|
|
const pending = new Map();
|
|
let runtimeExecutionReady = false;
|
|
let startStatus = "blocked_browser_python_wasm_runtime_missing";
|
|
|
|
function rejectPending(error) {
|
|
for (const { reject, timer } of pending.values()) {
|
|
clearTimeout(timer);
|
|
reject(error);
|
|
}
|
|
pending.clear();
|
|
}
|
|
|
|
function request(type, payload = {}) {
|
|
if (!worker) {
|
|
return Promise.reject(new Error("Python remap browser worker is not started."));
|
|
}
|
|
const id = makeRequestId();
|
|
return new Promise((resolve, reject) => {
|
|
const timer = setTimeout(() => {
|
|
pending.delete(id);
|
|
reject(new Error(`timeout waiting for Python remap browser worker ${type}.`));
|
|
}, timeoutMs);
|
|
pending.set(id, { resolve, reject, timer });
|
|
worker.postMessage({ id, type, ...payload });
|
|
});
|
|
}
|
|
|
|
function handleMessage(event) {
|
|
const message = event.data ?? {};
|
|
const waiter = pending.get(message.id);
|
|
if (!waiter) {
|
|
return;
|
|
}
|
|
pending.delete(message.id);
|
|
clearTimeout(waiter.timer);
|
|
if (message.ok === false) {
|
|
waiter.reject(new Error(message.error ?? `Python remap browser worker ${message.type ?? "request"} failed.`));
|
|
return;
|
|
}
|
|
waiter.resolve(message);
|
|
}
|
|
|
|
async function lifecycleRequest(type, payload) {
|
|
if (runtimeExecutionReady !== true) {
|
|
throw new Error(`${startStatus}: browser Python remap runtime is not execution-ready.`);
|
|
}
|
|
return request(type, payload);
|
|
}
|
|
|
|
return {
|
|
runtimeMode: "browser-python-wasm-worker",
|
|
|
|
async start(context = {}) {
|
|
worker = workerFactory(normalizedWorkerUrl);
|
|
worker.addEventListener("message", handleMessage);
|
|
worker.addEventListener("error", (event) => {
|
|
rejectPending(new Error(event.message ?? "Python remap browser worker error."));
|
|
});
|
|
const result = await request("start", {
|
|
...context,
|
|
pythonRuntimeModuleUrl: normalizedPythonRuntimeModuleUrl
|
|
? String(normalizedPythonRuntimeModuleUrl)
|
|
: null,
|
|
});
|
|
runtimeExecutionReady = result.runtimeExecutionReady === true;
|
|
startStatus = result.status ?? (runtimeExecutionReady
|
|
? "browser_python_remap_wasm_runtime_ready"
|
|
: "blocked_browser_python_wasm_runtime_missing");
|
|
return {
|
|
status: startStatus,
|
|
runtimeExecutionReady,
|
|
};
|
|
},
|
|
|
|
async initializePython(payload) {
|
|
return lifecycleRequest("initializePython", payload);
|
|
},
|
|
|
|
async applyIniPythonPath(payload) {
|
|
return lifecycleRequest("applyIniPythonPath", payload);
|
|
},
|
|
|
|
async executeTopLevel(payload) {
|
|
return lifecycleRequest("executeTopLevel", payload);
|
|
},
|
|
|
|
async importModule(payload) {
|
|
return lifecycleRequest("importModule", payload);
|
|
},
|
|
|
|
async lookupCallable(payload) {
|
|
return lifecycleRequest("lookupCallable", payload);
|
|
},
|
|
|
|
async invokeGenerator(payload) {
|
|
return lifecycleRequest("invokeGenerator", payload);
|
|
},
|
|
|
|
async observeFirstYield(payload) {
|
|
return lifecycleRequest("observeFirstYield", payload);
|
|
},
|
|
|
|
async finishGenerator(payload) {
|
|
return lifecycleRequest("finishGenerator", payload);
|
|
},
|
|
|
|
async stageNgcRemapAsset(payload) {
|
|
return lifecycleRequest("stageNgcRemapAsset", payload);
|
|
},
|
|
|
|
async rejectNgcOnlyStandalone(payload) {
|
|
return lifecycleRequest("rejectNgcOnlyStandalone", payload);
|
|
},
|
|
|
|
async exportInterpreterState(payload) {
|
|
return lifecycleRequest("exportInterpreterState", payload);
|
|
},
|
|
|
|
async exportCanonicalEvents(payload) {
|
|
return lifecycleRequest("exportCanonicalEvents", payload);
|
|
},
|
|
|
|
async exportDiagnostics(payload) {
|
|
return lifecycleRequest("exportDiagnostics", payload);
|
|
},
|
|
|
|
async close() {
|
|
if (worker) {
|
|
try {
|
|
await request("close");
|
|
} catch {
|
|
// The worker may be blocked or already gone; termination below is authoritative.
|
|
}
|
|
}
|
|
rejectPending(new Error("Python remap browser worker closed."));
|
|
worker?.terminate();
|
|
worker = null;
|
|
},
|
|
};
|
|
}
|