Optimize XYZAC motion updates and persist power-off recovery

This commit is contained in:
2026-08-29 04:52:44 +08:00
parent a97971ea19
commit f6e545018e
17 changed files with 479 additions and 74 deletions

View File

@@ -1,7 +1,20 @@
import { CONTEXT_ID, PROTOCOL_SCHEMA, isEnvelope, type MessageEnvelope } from "./protocol";
import { attachPersistedPowerOffCheckpoint, clearPersistedPowerOffCheckpoint, persistPowerOffCheckpoint } from "./power-off-checkpoint-storage";
type Listener = (message: MessageEnvelope) => void;
function commandError(message: MessageEnvelope): Error {
const payload = message.payload && typeof message.payload === "object" ? message.payload as Record<string, unknown> : {};
const error = new Error(String(payload.reason ?? payload.gate_reason ?? payload.message_key ?? payload.code ?? "worker_error"));
Object.assign(error, {
code: String(payload.code ?? "worker_error"),
reason: payload.reason ?? payload.gate_reason ?? null,
message_key: payload.message_key ?? null,
response: message,
});
return error;
}
export class ReactWorkerClient {
private readonly worker: Worker;
private readonly contextId: string;
@@ -19,11 +32,14 @@ export class ReactWorkerClient {
this.sessionId = sessionId;
this.worker.onmessage = (event: MessageEvent<unknown>) => {
if (!isEnvelope(event.data)) return;
const persistence = persistPowerOffCheckpoint(event.data);
if (persistence && event.data.payload && typeof event.data.payload === "object") Object.assign(event.data.payload, { recovery_persistence: persistence });
clearPersistedPowerOffCheckpoint(event.data);
for (const listener of this.listeners) listener(event.data);
const pending = this.pending.get(event.data.seq);
if (pending) {
this.pending.delete(event.data.seq);
if (event.data.kind === "ERROR" || event.data.payload && typeof event.data.payload === "object" && (event.data.payload as { status?: string }).status === "blocked") pending.reject(new Error(String((event.data.payload as { code?: string }).code ?? "worker_error")));
if (event.data.kind === "ERROR" || event.data.payload && typeof event.data.payload === "object" && (event.data.payload as { status?: string }).status === "blocked") pending.reject(commandError(event.data));
else pending.resolve(event.data);
}
};
@@ -45,7 +61,8 @@ export class ReactWorkerClient {
subscribe(listener: Listener): () => void { this.listeners.add(listener); return () => this.listeners.delete(listener); }
send(kind: string, payload: unknown = {}, operationId?: string): Promise<MessageEnvelope> {
const message: MessageEnvelope = { schema_version: PROTOCOL_SCHEMA, kind, context_id: this.contextId, session_id: this.sessionId, seq: ++this.sequence, ...(operationId ? { operation_id: operationId } : {}), payload };
const nextPayload = kind === "LOAD_WORKSPACE" ? attachPersistedPowerOffCheckpoint(payload) : payload;
const message: MessageEnvelope = { schema_version: PROTOCOL_SCHEMA, kind, context_id: this.contextId, session_id: this.sessionId, seq: ++this.sequence, ...(operationId ? { operation_id: operationId } : {}), payload: nextPayload };
return new Promise((resolve, reject) => { this.pending.set(message.seq, { resolve, reject }); this.worker.postMessage(message); });
}