mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 14:20:35 +08:00
142 lines
3.8 KiB
JavaScript
142 lines
3.8 KiB
JavaScript
import { solveLayoutWithJs } from "./graph-layout-solver.js";
|
|
|
|
let nativeSolver = null;
|
|
let nativeLoadAttempted = false;
|
|
let nativeLoadError = "";
|
|
let readNativeModuleStatus = null;
|
|
const canceledJobIds = new Set();
|
|
const activeJobIds = new Set();
|
|
|
|
async function ensureNativeSolver() {
|
|
if (nativeLoadAttempted) return nativeSolver;
|
|
nativeLoadAttempted = true;
|
|
|
|
try {
|
|
const nativeModule = await import("../vendor/wasm/stbme_core.js");
|
|
const solveLayout =
|
|
nativeModule?.solveLayout || nativeModule?.default?.solveLayout || null;
|
|
nativeSolver = typeof solveLayout === "function" ? solveLayout : null;
|
|
readNativeModuleStatus =
|
|
typeof nativeModule?.getNativeModuleStatus === "function"
|
|
? nativeModule.getNativeModuleStatus
|
|
: null;
|
|
} catch (error) {
|
|
nativeLoadError = error?.message || String(error);
|
|
nativeSolver = null;
|
|
}
|
|
|
|
return nativeSolver;
|
|
}
|
|
|
|
async function solveLayout(payload = {}) {
|
|
const nativeRequested = payload?.nativeRequested === true;
|
|
if (nativeRequested) {
|
|
const solver = await ensureNativeSolver();
|
|
if (solver) {
|
|
try {
|
|
const nativeResult = await solver(payload);
|
|
const nativeStatus =
|
|
typeof readNativeModuleStatus === "function"
|
|
? readNativeModuleStatus()
|
|
: null;
|
|
if (
|
|
nativeResult &&
|
|
nativeResult.ok === true &&
|
|
nativeResult.positions instanceof Float32Array
|
|
) {
|
|
return {
|
|
...nativeResult,
|
|
usedNative: true,
|
|
diagnostics: {
|
|
...(nativeResult.diagnostics || {}),
|
|
solver: "rust-wasm",
|
|
moduleSource: String(nativeStatus?.source || ""),
|
|
nativeLoadError: String(nativeStatus?.error || nativeLoadError || ""),
|
|
},
|
|
};
|
|
}
|
|
} catch (error) {
|
|
return {
|
|
ok: false,
|
|
skipped: true,
|
|
reason: "native-solver-failed",
|
|
error: error?.message || String(error),
|
|
nativeLoadError,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
const jsResult = solveLayoutWithJs(payload);
|
|
return {
|
|
...jsResult,
|
|
usedNative: false,
|
|
nativeLoadError,
|
|
};
|
|
}
|
|
|
|
self.addEventListener("message", async (event) => {
|
|
const message = event?.data || {};
|
|
if (message.type === "cancel-layout") {
|
|
const canceledJobId = Number(message.jobId);
|
|
if (Number.isFinite(canceledJobId)) {
|
|
canceledJobIds.add(canceledJobId);
|
|
}
|
|
return;
|
|
}
|
|
if (message.type !== "solve-layout") return;
|
|
|
|
const jobId = Number(message.jobId);
|
|
if (!Number.isFinite(jobId)) return;
|
|
if (canceledJobIds.has(jobId)) {
|
|
canceledJobIds.delete(jobId);
|
|
return;
|
|
}
|
|
activeJobIds.add(jobId);
|
|
const fallbackErrorResult = (errorMessage = "unknown-worker-error") => ({
|
|
ok: false,
|
|
skipped: true,
|
|
reason: "worker-exception",
|
|
error: String(errorMessage || "unknown-worker-error"),
|
|
});
|
|
|
|
try {
|
|
const result = await solveLayout(message.payload || {});
|
|
if (!activeJobIds.has(jobId) || canceledJobIds.has(jobId)) {
|
|
activeJobIds.delete(jobId);
|
|
canceledJobIds.delete(jobId);
|
|
return;
|
|
}
|
|
activeJobIds.delete(jobId);
|
|
if (result?.positions instanceof Float32Array) {
|
|
self.postMessage(
|
|
{
|
|
type: "layout-result",
|
|
jobId,
|
|
result,
|
|
},
|
|
[result.positions.buffer],
|
|
);
|
|
return;
|
|
}
|
|
|
|
self.postMessage({
|
|
type: "layout-result",
|
|
jobId,
|
|
result,
|
|
});
|
|
} catch (error) {
|
|
if (!activeJobIds.has(jobId) || canceledJobIds.has(jobId)) {
|
|
activeJobIds.delete(jobId);
|
|
canceledJobIds.delete(jobId);
|
|
return;
|
|
}
|
|
activeJobIds.delete(jobId);
|
|
self.postMessage({
|
|
type: "layout-result",
|
|
jobId,
|
|
result: fallbackErrorResult(error?.message || String(error)),
|
|
});
|
|
}
|
|
});
|