forked from 1b-agent/opencadstudio-upstream
Ported fromd719fb77(#1717); the hatch draw-order, PDF and recovery-settle hunks stay out (main owns those paths). - La16 was still billed at 4 B/px: the no-conversion special case keyed on native_bpp == 4, which La16 also is — but only Rgba8 is a real move in into_rgba8, so La16's decode peak is 8. The case now keys on the color type, and a table test pins every layout's peak (plus GIF's screen+frame 8) so the accounting can't silently drift. - json_values_match: an integer beyond f64 precision no longer matches a float it merely rounds onto; a mixed pair matches only when the float is whole and converts back to exactly that integer (also the fuzz finding of9262d63f). - ocs-control.js resolves `ready` with the API object instead of window.ocsControl, which is still undefined when the bridge already exists as the script runs (built before the first settle, avoiding the temporal-dead-zone throw of a later const); DATALINK on web says the typed path is superseded by the picker instead of silently discarding it. (cherry picked from commitd719fb77)
77 lines
2.8 KiB
JavaScript
77 lines
2.8 KiB
JavaScript
// Web automation convenience API (#1349).
|
|
//
|
|
// The wasm module exposes the control bridge through `window.wasmBindings`
|
|
// (ocs_control_submit / ocs_control_take). This module wraps it in promises:
|
|
//
|
|
// await window.ocsControl.ready resolves once the bridge exists
|
|
// window.addEventListener("ocs-ready", …) fired once, at the same moment
|
|
// await window.ocsControl.request({...}) one control request -> final reply
|
|
//
|
|
// Hosts that intend to automate from the start should set
|
|
// localStorage["opencadstudio.automation"] = "1" before the page loads so the
|
|
// startup donation prompt never appears (see docs/automation/web.md).
|
|
(() => {
|
|
if (window.ocsControl) return;
|
|
const bridge = () => {
|
|
const api = window.wasmBindings;
|
|
return api && api.ocs_control_submit && api.ocs_control_take ? api : null;
|
|
};
|
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
let readyResolve;
|
|
const ready = new Promise(resolve => { readyResolve = resolve; });
|
|
// Built before the first settle() can run (`request` is a hoisted
|
|
// function declaration): `ready` resolves with this object even when the
|
|
// bridge already exists as the script runs.
|
|
const apiObject = {ready, request};
|
|
const settle = () => {
|
|
readyResolve(apiObject);
|
|
window.dispatchEvent(new Event("ocs-ready"));
|
|
};
|
|
const poll = setInterval(() => {
|
|
if (bridge()) {
|
|
clearInterval(poll);
|
|
settle();
|
|
}
|
|
}, 50);
|
|
if (bridge()) {
|
|
clearInterval(poll);
|
|
settle();
|
|
}
|
|
|
|
// Submit one request and poll take() until the app stores its reply.
|
|
async function exchange(api, payload, pollMs, deadline) {
|
|
const ticket = api.ocs_control_submit(JSON.stringify(payload));
|
|
for (;;) {
|
|
const raw = api.ocs_control_take(ticket);
|
|
if (raw) return JSON.parse(raw);
|
|
if (performance.now() >= deadline) {
|
|
throw new Error("ocs-control: timed out: " + JSON.stringify(payload));
|
|
}
|
|
await sleep(pollMs);
|
|
}
|
|
}
|
|
|
|
// One control request. Replies that are still `accepted`/`running` (an
|
|
// async open, capture or save) are followed through `op:"operation"` until
|
|
// a final status arrives. Resolves with the final reply object; rejects
|
|
// only on timeout or a missing bridge.
|
|
async function request(payload, options = {}) {
|
|
const pollMs = options.pollMs ?? 50;
|
|
const deadline = performance.now() + (options.timeoutMs ?? 120000);
|
|
const api = bridge();
|
|
if (!api) {
|
|
throw new Error("ocs-control: bridge not ready (await ocsControl.ready)");
|
|
}
|
|
let reply = await exchange(api, payload, pollMs, deadline);
|
|
while (["accepted", "running"].includes(reply.status) && reply.request_id) {
|
|
await sleep(pollMs);
|
|
reply = await exchange(
|
|
api, {op: "operation", request_id: reply.request_id}, pollMs, deadline);
|
|
}
|
|
return reply;
|
|
}
|
|
|
|
window.ocsControl = apiObject;
|
|
})();
|