Optimize XYZAC motion updates and persist power-off recovery
This commit is contained in:
@@ -1,11 +1,43 @@
|
||||
export const CONTEXT_ID = "linuxcnc-2.10.0-pre0-wasm-m1-py-c1";
|
||||
export const PROTOCOL_SCHEMA = 1;
|
||||
const POWER_OFF_CHECKPOINT_KEY = "linuxcnc-web-wasm:xyzac-power-off-checkpoint";
|
||||
let CLIENT_INSTANCE = 0;
|
||||
|
||||
function isObject(value) {
|
||||
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function persistPowerOffCheckpoint(message) {
|
||||
const payload = isObject(message?.payload) ? message.payload : {};
|
||||
if (message.kind !== "COMMAND_RESULT" || payload.status !== "verified" || payload.command !== "POWER" || payload.active !== false || !isObject(payload.recovery_checkpoint)) return;
|
||||
try { globalThis.localStorage?.setItem(POWER_OFF_CHECKPOINT_KEY, JSON.stringify(payload.recovery_checkpoint)); } catch { /* checkpoint remains visible in the response */ }
|
||||
}
|
||||
|
||||
function attachPowerOffCheckpoint(payload) {
|
||||
if (!isObject(payload)) return payload;
|
||||
try {
|
||||
const raw = globalThis.localStorage?.getItem(POWER_OFF_CHECKPOINT_KEY);
|
||||
return raw ? { ...payload, recovery_checkpoint: JSON.parse(raw) } : payload;
|
||||
} catch { return payload; }
|
||||
}
|
||||
|
||||
function clearPowerOffCheckpoint(message) {
|
||||
const payload = isObject(message?.payload) ? message.payload : {};
|
||||
if (message.kind !== "COMMAND_RESULT" || payload.status !== "verified" || payload.command !== "POWER" || payload.active !== true) return;
|
||||
try { globalThis.localStorage?.removeItem(POWER_OFF_CHECKPOINT_KEY); } catch { /* cleanup is best effort */ }
|
||||
}
|
||||
|
||||
function commandError(message) {
|
||||
const payload = isObject(message?.payload) ? message.payload : {};
|
||||
const reason = payload.reason ?? payload.gate_reason ?? payload.message_key ?? payload.code ?? "worker_error";
|
||||
return Object.assign(new Error(String(reason)), {
|
||||
code: payload.code ?? "worker_error",
|
||||
reason: payload.reason ?? payload.gate_reason ?? null,
|
||||
message_key: payload.message_key ?? null,
|
||||
response: message,
|
||||
});
|
||||
}
|
||||
|
||||
export class WorkerClient {
|
||||
constructor({ worker = null, workerFactory = null, contextId = CONTEXT_ID, sessionId = null, timeoutMs = 10000, maxPending = 64 } = {}) {
|
||||
this.contextId = contextId;
|
||||
@@ -32,6 +64,9 @@ export class WorkerClient {
|
||||
}
|
||||
|
||||
#receive(message) {
|
||||
const persistence = persistPowerOffCheckpoint(message);
|
||||
if (persistence && isObject(message?.payload)) message.payload.recovery_persistence = persistence;
|
||||
clearPowerOffCheckpoint(message);
|
||||
this.#emit(message);
|
||||
if (!isObject(message)) return;
|
||||
const operationId = message.operation_id ?? message.payload?.operation_id;
|
||||
@@ -41,9 +76,7 @@ export class WorkerClient {
|
||||
this.pending.delete(operationId ?? `seq:${message.seq}`);
|
||||
if (operationId) this.completed.set(operationId, message);
|
||||
if (message.kind === "ERROR" || message.payload?.status === "error" || message.payload?.status === "blocked") {
|
||||
const error = new Error(message.payload?.message_key ?? message.payload?.code ?? "worker_error");
|
||||
error.response = message;
|
||||
pending.reject(error);
|
||||
pending.reject(commandError(message));
|
||||
} else pending.resolve(message);
|
||||
}
|
||||
|
||||
@@ -68,7 +101,7 @@ export class WorkerClient {
|
||||
seq,
|
||||
kind,
|
||||
...(operationId ? { operation_id: operationId } : {}),
|
||||
payload,
|
||||
payload: kind === "LOAD_WORKSPACE" ? attachPowerOffCheckpoint(payload) : payload,
|
||||
};
|
||||
let resolvePromise;
|
||||
let rejectPromise;
|
||||
|
||||
Reference in New Issue
Block a user