Files
FreeCADWasmDev/web/src/assembly-native-facade.ts
wangdequan 9a7c4f0335 Save FreeCAD Web workspace sources and user validation evidence
IFC native binding remains incomplete; preserve accurate test results.
2026-09-15 22:01:58 +08:00

24 lines
3.7 KiB
TypeScript

import { FacadeHandlerError, FacadeRequest, FacadeResponse, FacadeSerialQueue, createRequest, isFacadeRequest } from "./facade-envelope.js";
export const ASSEMBLY_NATIVE_SCHEMA = "freecad-web-assembly/native-type-probe/v1" as const;
export const ASSEMBLY_NATIVE_COMMAND = "assembly.nativeTypeProbe" as const;
export const ASSEMBLY_NATIVE_FIXTURE = { schema: ASSEMBLY_NATIVE_SCHEMA, module: "Assembly", typeName: "Assembly::AssemblyObject" } as const;
export interface AssemblyNativePayload { schema: typeof ASSEMBLY_NATIVE_SCHEMA; module: "Assembly"; typeName: string }
export interface AssemblyNativeResult { schema: typeof ASSEMBLY_NATIVE_SCHEMA; module: "Assembly"; typeName: string; initialized: true; source: "freecad-source"; resourcesReleased: true }
export interface AssemblyNativeKernel { ccall(name: string, returnType: "number" | "string", argTypes?: string[], args?: unknown[]): number | string }
export type AssemblyNativeRequest = FacadeRequest<AssemblyNativePayload>; export type AssemblyNativeResponse = FacadeResponse<AssemblyNativeResult>;
export function createAssemblyNativeRequest(id: string, payload: AssemblyNativePayload = ASSEMBLY_NATIVE_FIXTURE): AssemblyNativeRequest { return createRequest(id, ASSEMBLY_NATIVE_COMMAND, payload, "assembly-native"); }
export function isAssemblyNativeRequest(value: unknown): value is AssemblyNativeRequest { if (!isFacadeRequest(value)) return false; const request = value as AssemblyNativeRequest; return request.command === ASSEMBLY_NATIVE_COMMAND && request.payload?.schema === ASSEMBLY_NATIVE_SCHEMA && request.payload?.module === "Assembly" && typeof request.payload.typeName === "string" && request.payload.typeName.length > 0; }
export async function handleAssemblyNative(payload: AssemblyNativePayload, signal: AbortSignal, source: AssemblyNativeKernel | Promise<AssemblyNativeKernel>): Promise<AssemblyNativeResult> {
if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled");
if (!isAssemblyNativeRequest(createAssemblyNativeRequest("validation", payload))) throw new FacadeHandlerError("invalid_fixture", "Assembly native type probe payload is invalid");
const kernel = await source;
if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled");
if (Number(kernel.ccall("fc_web_assembly_initialize", "number", ["string"], ["AssemblyApp"])) !== 1) throw new FacadeHandlerError(String(kernel.ccall("fc_web_assembly_error_code", "string") || "native_error"), String(kernel.ccall("fc_web_assembly_error_message", "string") || "Assembly native initialization failed"));
if (Number(kernel.ccall("fc_web_assembly_type_probe", "number", ["string"], [payload.typeName])) !== 1) throw new FacadeHandlerError(String(kernel.ccall("fc_web_assembly_error_code", "string") || "type_not_found"), String(kernel.ccall("fc_web_assembly_error_message", "string") || "Assembly type probe failed"));
const handle = Number(kernel.ccall("fc_web_assembly_create_handle", "number", ["string"], [payload.typeName]));
if (handle <= 0 || Number(kernel.ccall("fc_web_assembly_release_handle", "number", ["number"], [handle])) !== 1 || Number(kernel.ccall("fc_web_assembly_active_handles", "number")) !== 0) throw new FacadeHandlerError("resource_leak", "Assembly native type handle was not released");
return { schema: ASSEMBLY_NATIVE_SCHEMA, module: "Assembly", typeName: String(kernel.ccall("fc_web_assembly_last_type", "string")), initialized: true, source: "freecad-source", resourcesReleased: true };
}
export function dispatchAssemblyNative(queue: FacadeSerialQueue, request: AssemblyNativeRequest, source: AssemblyNativeKernel | Promise<AssemblyNativeKernel>): Promise<AssemblyNativeResponse> { return queue.dispatch(request, (payload, signal) => handleAssemblyNative(payload, signal, source)); }