import { FacadeHandlerError, FacadeRequest, FacadeResponse, FacadeSerialQueue, createRequest, isFacadeRequest } from "./facade-envelope.js"; import type { JtReaderKernelModule } from "./jtreader-facade.js"; export const JTREADER_PERSISTENCE_SCHEMA = "freecad-web-jtreader/save-reopen/v1" as const; export const JTREADER_PERSISTENCE_COMMAND = "jtreader.saveReopen" as const; export const JTREADER_PERSISTENCE_PATH = "/tmp/JtReaderKernel.FCStd" as const; export interface JtReaderPersistencePayload { schema: typeof JTREADER_PERSISTENCE_SCHEMA; module: "JtReader"; action: "save/reopen"; path: string; } export interface JtReaderPersistenceResult { schema: typeof JTREADER_PERSISTENCE_SCHEMA; module: "JtReader"; action: "save/reopen"; format: ".fcstd"; path: typeof JTREADER_PERSISTENCE_PATH; size: number; objectCount: 1; objectType: "App::InventorObject"; roundTrip: true; resourcesReleased: true; } export type JtReaderPersistenceRequest = FacadeRequest; export type JtReaderPersistenceResponse = FacadeResponse; export const JTREADER_PERSISTENCE_FIXTURE: JtReaderPersistencePayload = { schema: JTREADER_PERSISTENCE_SCHEMA, module: "JtReader", action: "save/reopen", path: JTREADER_PERSISTENCE_PATH, }; export function createJtReaderPersistenceRequest(requestId: string, payload: JtReaderPersistencePayload = JTREADER_PERSISTENCE_FIXTURE): JtReaderPersistenceRequest { return createRequest(requestId, JTREADER_PERSISTENCE_COMMAND, payload, "jtreader-persistence-doc"); } export function isJtReaderPersistenceRequest(value: unknown): value is JtReaderPersistenceRequest { if (!isFacadeRequest(value)) return false; const request = value as JtReaderPersistenceRequest; const payload = request.payload; return request.command === JTREADER_PERSISTENCE_COMMAND && payload?.schema === JTREADER_PERSISTENCE_SCHEMA && payload?.module === "JtReader" && payload?.action === "save/reopen" && typeof payload?.path === "string"; } const kernelString = (kernel: JtReaderKernelModule, name: string) => kernel.ccall(name, "string") as string; const kernelNumber = (kernel: JtReaderKernelModule, name: string) => kernel.ccall(name, "number") as number; export async function handleJtReaderPersistence(payload: JtReaderPersistencePayload, signal: AbortSignal, kernelSource: JtReaderKernelModule | Promise): Promise { if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled"); if (!isJtReaderPersistenceRequest(createJtReaderPersistenceRequest("validation", payload)) || payload.schema !== JTREADER_PERSISTENCE_SCHEMA || payload.module !== "JtReader" || payload.action !== "save/reopen") { throw new FacadeHandlerError("invalid_fixture", "JtReader persistence fixture is invalid", { field: "action" }); } if (payload.path !== JTREADER_PERSISTENCE_PATH) { throw new FacadeHandlerError("invalid_path", "JtReader FCStd path is not writable", { path: payload.path }); } const kernel = await kernelSource; if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled"); if (kernelNumber(kernel, "fc_web_jtreader_save_reopen") !== 1) { throw new FacadeHandlerError( kernelString(kernel, "fc_web_jtreader_error_code") || "save_reopen_failed", kernelString(kernel, "fc_web_jtreader_error_message") || "JtReader FCStd save/reopen failed", ); } return { schema: JTREADER_PERSISTENCE_SCHEMA, module: "JtReader", action: "save/reopen", format: ".fcstd", path: kernelString(kernel, "fc_web_jtreader_persistence_path") as typeof JTREADER_PERSISTENCE_PATH, size: kernelNumber(kernel, "fc_web_jtreader_persistence_size"), objectCount: kernelNumber(kernel, "fc_web_jtreader_persistence_object_count") as 1, objectType: kernelString(kernel, "fc_web_jtreader_persistence_object_type") as "App::InventorObject", roundTrip: true, resourcesReleased: true, }; } export function dispatchJtReaderPersistence(queue: FacadeSerialQueue, request: JtReaderPersistenceRequest, kernelSource: JtReaderKernelModule | Promise): Promise { return queue.dispatch(request, (payload, signal) => handleJtReaderPersistence(payload, signal, kernelSource)); }