26 lines
4.1 KiB
TypeScript
26 lines
4.1 KiB
TypeScript
import { FacadeHandlerError, FacadeRequest, FacadeResponse, FacadeSerialQueue, createRequest, isFacadeRequest } from "./facade-envelope.js";
|
|
|
|
export const MESH_PERSISTENCE_SCHEMA = "freecad-web-mesh/save-reopen/v1" as const;
|
|
export const MESH_PERSISTENCE_COMMAND = "mesh.saveReopen" as const;
|
|
export const MESH_PERSISTENCE_PATH = "/tmp/MeshAction05.FCStd" as const;
|
|
export interface MeshPersistencePayload { schema: typeof MESH_PERSISTENCE_SCHEMA; module: "Mesh"; action: "save/reopen"; path: string }
|
|
export interface MeshPersistenceResult { schema: typeof MESH_PERSISTENCE_SCHEMA; module: "Mesh"; action: "save/reopen"; format: "FCStd"; path: typeof MESH_PERSISTENCE_PATH; size: number; objectType: "Mesh::Feature"; objectCount: 1; facetCount: 1; pointCount: 3; roundTrip: true; bytes?: ArrayBuffer }
|
|
export interface MeshPersistenceKernel { ccall(name: string, type: "number" | "string", argTypes?: string[], args?: unknown[]): number | string; FS?: { readFile(path: string): Uint8Array } }
|
|
export type MeshPersistenceRequest = FacadeRequest<MeshPersistencePayload>; export type MeshPersistenceResponse = FacadeResponse<MeshPersistenceResult>;
|
|
export const MESH_PERSISTENCE_FIXTURE: MeshPersistencePayload = { schema: MESH_PERSISTENCE_SCHEMA, module: "Mesh", action: "save/reopen", path: MESH_PERSISTENCE_PATH };
|
|
export function createMeshPersistenceRequest(requestId: string, payload: MeshPersistencePayload = MESH_PERSISTENCE_FIXTURE): MeshPersistenceRequest { return createRequest(requestId, MESH_PERSISTENCE_COMMAND, payload, "mesh-persistence"); }
|
|
export function isMeshPersistenceRequest(value: unknown): value is MeshPersistenceRequest { if (!isFacadeRequest(value)) return false; const request = value as MeshPersistenceRequest; const payload = request.payload; return request.command === MESH_PERSISTENCE_COMMAND && payload?.schema === MESH_PERSISTENCE_SCHEMA && payload?.module === "Mesh" && payload?.action === "save/reopen" && typeof payload?.path === "string"; }
|
|
const number = (kernel: MeshPersistenceKernel, name: string) => Number(kernel.ccall(name, "number"));
|
|
const text = (kernel: MeshPersistenceKernel, name: string) => String(kernel.ccall(name, "string"));
|
|
export async function handleMeshPersistence(payload: MeshPersistencePayload, signal: AbortSignal, source: MeshPersistenceKernel | Promise<MeshPersistenceKernel>): Promise<MeshPersistenceResult> {
|
|
if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled");
|
|
if (!isMeshPersistenceRequest(createMeshPersistenceRequest("validation", payload)) || payload.path !== MESH_PERSISTENCE_PATH) throw new FacadeHandlerError("invalid_path", "Mesh FCStd path is not locked", { path: payload.path });
|
|
const kernel = await source;
|
|
if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled");
|
|
if (number(kernel, "fc_web_mesh_save_reopen") !== 1) throw new FacadeHandlerError(text(kernel, "fc_web_mesh_persistence_error_code") || "save_reopen_failed", text(kernel, "fc_web_mesh_persistence_error_message") || "Mesh FCStd save/reopen failed");
|
|
const result: MeshPersistenceResult = { schema: MESH_PERSISTENCE_SCHEMA, module: "Mesh", action: "save/reopen", format: "FCStd", path: text(kernel, "fc_web_mesh_persistence_path") as typeof MESH_PERSISTENCE_PATH, size: number(kernel, "fc_web_mesh_persistence_size"), objectType: text(kernel, "fc_web_mesh_persistence_object_type") as "Mesh::Feature", objectCount: number(kernel, "fc_web_mesh_persistence_object_count") as 1, facetCount: number(kernel, "fc_web_mesh_persistence_facets") as 1, pointCount: number(kernel, "fc_web_mesh_persistence_points") as 3, roundTrip: (number(kernel, "fc_web_mesh_persistence_round_trip") === 1) as true };
|
|
if (kernel.FS) { try { result.bytes = kernel.FS.readFile(result.path).slice().buffer; } catch { /* Byte transfer is optional when a probe omits FS export. */ } }
|
|
return result;
|
|
}
|
|
export function dispatchMeshPersistence(queue: FacadeSerialQueue, request: MeshPersistenceRequest, source: MeshPersistenceKernel | Promise<MeshPersistenceKernel>): Promise<MeshPersistenceResponse> { return queue.dispatch(request, (payload, signal) => handleMeshPersistence(payload, signal, source)); }
|