推进 OPFS 会话快照清单能力
This commit is contained in:
54
text10.txt
54
text10.txt
@@ -230,6 +230,60 @@ groups,重点检查 `saveMachineTextFiles(...)` 相关输入是否已有可复
|
||||
- 把 save API 输入对象提成无用常量;
|
||||
- 触碰 runtime、SDK、OPFS bridge 或 LinuxCNC-owned semantics。
|
||||
|
||||
二、2026-06-14 继续执行记录:browser OPFS session snapshot manifest helper
|
||||
|
||||
本轮按“暂停性能测试,进行实质性功能推进”的要求,补充了一个新的 OPFS/runtime
|
||||
能力:生成可恢复的机器会话快照清单,范围仍局限在 `runtime/opfs` 与对应 smoke。
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 `wasm-port/runtime/opfs/snapshot-store.js` 新增
|
||||
`createMachineSessionSnapshotPayload(machineId, options)`;
|
||||
- 该 helper 基于现有 `path-model` 生成机器级 session snapshot payload,默认包含
|
||||
`ini`、`parameters`、`toolTable`,可选包含 `gcode`;
|
||||
- 支持自定义 `iniOpfsPath`、`parameterOpfsPath`、`toolTableOpfsPath`、`gcodeOpfsPath`;
|
||||
- 支持自定义 `iniFilename`、`parameterFilename`、`toolTableFilename`、`gcodeFilename`;
|
||||
- 在 Node OPFS smoke 与 browser INI panel smoke 中补了覆盖,验证默认路径、自定义
|
||||
文件名和 G-code 路径均能按预期生成;
|
||||
- 未改变 session snapshot 的格式、版本、存储位置或既有 save/load 行为;
|
||||
- 未改变 OPFS bridge behavior、file-service、SDK planner、interpreter、INI、tool、
|
||||
parameter 或 LinuxCNC-owned runtime semantics。
|
||||
|
||||
验证已通过:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
wasm-port/tests/opfs/node/verify_file_service.sh
|
||||
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh
|
||||
wasm-port/tools/verify_vendor_sync.sh
|
||||
wasm-port/tools/verify_no_standalone_cnc_semantics.sh
|
||||
SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_interp_wasm.sh
|
||||
SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
|
||||
wasm-port/tests/host/verify_host_smokes.sh
|
||||
```
|
||||
|
||||
关键输出:
|
||||
|
||||
```text
|
||||
opfs_file_service_node_smoke=ok
|
||||
browser_ini_opfs_smoke=ok
|
||||
vendor sync up to date
|
||||
standalone CNC semantics guard complete
|
||||
interp_wasm_node_smoke=ok
|
||||
sim_configs_wasm_node_inventory_executed=28
|
||||
sim_configs_wasm_node_inventory_passed=28
|
||||
sim_configs_wasm_node_inventory_skipped=131
|
||||
sim_configs_wasm_node_inventory_unexpected_fail=0
|
||||
browser_interp_smoke=ok
|
||||
host_wasm_opfs_browser_smokes=ok
|
||||
```
|
||||
|
||||
下一步建议:
|
||||
|
||||
继续把这个 helper 扩到更明确的实际入口,优先扫描 browser/Node 里已有的 session
|
||||
snapshot 调用是否能复用它,或者把 machine session 生成入口整理到更显式的 API;
|
||||
只做 OPFS/filesystem/browser boundary 相关功能推进,不碰 CNC 语义。
|
||||
|
||||
一、2026-06-14 继续执行记录:browser explicit readback path groups guard
|
||||
|
||||
本轮按 `text10.txt` 第一候选批次继续收敛 explicit session saved readback path groups,
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { loadTextFile, saveTextFile } from "./file-service.js";
|
||||
import { sessionSnapshotPath } from "./path-model.js";
|
||||
import {
|
||||
gcodeProgramPath,
|
||||
machineIniPath,
|
||||
normalizeOpfsPath,
|
||||
parameterFilePath,
|
||||
sessionSnapshotPath,
|
||||
toolTablePath,
|
||||
} from "./path-model.js";
|
||||
|
||||
export const SESSION_SNAPSHOT_FORMAT = "linuxcnc-wasm-session-snapshot";
|
||||
export const SESSION_SNAPSHOT_VERSION = 1;
|
||||
@@ -10,6 +17,38 @@ function assertPlainObject(value, label) {
|
||||
}
|
||||
}
|
||||
|
||||
function optionalOpfsPath(value, label) {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof value !== "string") {
|
||||
throw new Error(`${label} must be a string.`);
|
||||
}
|
||||
return normalizeOpfsPath(value);
|
||||
}
|
||||
|
||||
export function createMachineSessionSnapshotPayload(machineId, options = {}) {
|
||||
assertPlainObject(options, "machine session snapshot options");
|
||||
const ini = optionalOpfsPath(options.iniOpfsPath, "INI OPFS path") ??
|
||||
machineIniPath(machineId, options.iniFilename);
|
||||
const parameters = optionalOpfsPath(options.parameterOpfsPath, "parameter OPFS path") ??
|
||||
parameterFilePath(machineId, options.parameterFilename);
|
||||
const toolTable = optionalOpfsPath(options.toolTableOpfsPath, "tool table OPFS path") ??
|
||||
toolTablePath(machineId, options.toolTableFilename);
|
||||
const gcode = optionalOpfsPath(options.gcodeOpfsPath, "G-code OPFS path") ??
|
||||
(options.gcodeFilename === undefined ? undefined : gcodeProgramPath(options.gcodeFilename));
|
||||
|
||||
return {
|
||||
machineId,
|
||||
files: {
|
||||
ini,
|
||||
parameters,
|
||||
toolTable,
|
||||
...(gcode === undefined ? {} : { gcode }),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function createSessionSnapshot(sessionId, payload, options = {}) {
|
||||
sessionSnapshotPath(sessionId, options.filename);
|
||||
assertPlainObject(payload, "snapshot payload");
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
sessionSnapshotPath,
|
||||
} from "../../runtime/opfs/path-model.js";
|
||||
import {
|
||||
createMachineSessionSnapshotPayload,
|
||||
loadSessionSnapshot,
|
||||
saveSessionSnapshot,
|
||||
} from "../../runtime/opfs/snapshot-store.js";
|
||||
@@ -124,7 +125,26 @@ TOOL_TABLE = browser-tool.tbl
|
||||
await saveTextFile(opfsPath, iniText);
|
||||
assertEqual(await loadTextFile(opfsPath), iniText, "opfs roundtrip");
|
||||
|
||||
const snapshotPayload = { files: { ini: opfsPath } };
|
||||
const snapshotPayload = createMachineSessionSnapshotPayload("browser-smoke", {
|
||||
gcodeFilename: "browser-smoke.ngc",
|
||||
});
|
||||
assertEqual(snapshotPayload.machineId, "browser-smoke", "snapshot machine");
|
||||
assertEqual(snapshotPayload.files.ini, opfsPath, "snapshot payload INI");
|
||||
assertEqual(
|
||||
snapshotPayload.files.parameters,
|
||||
"linuxcnc/machines/browser-smoke/linuxcnc.var",
|
||||
"snapshot payload parameter file",
|
||||
);
|
||||
assertEqual(
|
||||
snapshotPayload.files.toolTable,
|
||||
"linuxcnc/machines/browser-smoke/tool.tbl",
|
||||
"snapshot payload tool table",
|
||||
);
|
||||
assertEqual(
|
||||
snapshotPayload.files.gcode,
|
||||
"linuxcnc/gcode/browser-smoke.ngc",
|
||||
"snapshot payload G-code",
|
||||
);
|
||||
const savedSnapshot = await saveSessionSnapshot(
|
||||
"browser-session",
|
||||
snapshotPayload,
|
||||
@@ -139,7 +159,28 @@ TOOL_TABLE = browser-tool.tbl
|
||||
assertEqual(loadedSnapshot.sessionId, "browser-session", "snapshot session");
|
||||
assertEqual(loadedSnapshot.createdAt, savedSnapshot.createdAt, "snapshot timestamp");
|
||||
assertEqual(loadedSnapshot.payload.files.ini, opfsPath, "snapshot payload");
|
||||
assertEqual(loadedSnapshot.payload.files.gcode, snapshotPayload.files.gcode, "snapshot G-code payload");
|
||||
assertEqual(loadedSnapshot.metadata.source, "browser-smoke", "snapshot metadata");
|
||||
const customMachineSnapshotPayload = createMachineSessionSnapshotPayload("browser-smoke", {
|
||||
parameterFilename: "browser-linuxcnc.var",
|
||||
toolTableFilename: "browser-tool.tbl",
|
||||
gcodeOpfsPath: "linuxcnc/gcode/browser-custom.ngc",
|
||||
});
|
||||
assertEqual(
|
||||
customMachineSnapshotPayload.files.parameters,
|
||||
"linuxcnc/machines/browser-smoke/browser-linuxcnc.var",
|
||||
"custom snapshot parameter file",
|
||||
);
|
||||
assertEqual(
|
||||
customMachineSnapshotPayload.files.toolTable,
|
||||
"linuxcnc/machines/browser-smoke/browser-tool.tbl",
|
||||
"custom snapshot tool table",
|
||||
);
|
||||
assertEqual(
|
||||
customMachineSnapshotPayload.files.gcode,
|
||||
"linuxcnc/gcode/browser-custom.ngc",
|
||||
"custom snapshot G-code",
|
||||
);
|
||||
assertEqual(
|
||||
sessionSnapshotPath("browser-session", "browser-custom-snapshot.json"),
|
||||
"linuxcnc/sessions/browser-session/browser-custom-snapshot.json",
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
toolTablePath,
|
||||
} from "../../../runtime/opfs/path-model.js";
|
||||
import {
|
||||
createMachineSessionSnapshotPayload,
|
||||
createSessionSnapshot,
|
||||
loadSessionSnapshot,
|
||||
saveSessionSnapshot,
|
||||
@@ -216,12 +217,38 @@ assertSessionSnapshotStoragePath(
|
||||
assertMachineFileStoragePaths("xyzab-tdr", defaultMachinePaths("xyzab-tdr"));
|
||||
assertMachineFileStoragePaths("xyzab-tdr", machineFilePaths("xyzab-tdr"));
|
||||
|
||||
const snapshotPayload = {
|
||||
const snapshotPayload = createMachineSessionSnapshotPayload("xyzab-tdr", {
|
||||
gcodeFilename: "fixture.ngc",
|
||||
});
|
||||
assert.deepEqual(snapshotPayload, {
|
||||
machineId: "xyzab-tdr",
|
||||
files: {
|
||||
ini: machineIniPath("xyzab-tdr"),
|
||||
parameters: parameterFilePath("xyzab-tdr"),
|
||||
toolTable: toolTablePath("xyzab-tdr"),
|
||||
gcode: gcodeProgramPath("fixture.ngc"),
|
||||
},
|
||||
};
|
||||
});
|
||||
assert.deepEqual(
|
||||
createMachineSessionSnapshotPayload("custom-machine", {
|
||||
parameterFilename: "custom.var",
|
||||
toolTableFilename: "custom-tool.tbl",
|
||||
gcodeOpfsPath: "linuxcnc/gcode/custom-fixture.ngc",
|
||||
}),
|
||||
{
|
||||
machineId: "custom-machine",
|
||||
files: {
|
||||
ini: "linuxcnc/machines/custom-machine/machine.ini",
|
||||
parameters: "linuxcnc/machines/custom-machine/custom.var",
|
||||
toolTable: "linuxcnc/machines/custom-machine/custom-tool.tbl",
|
||||
gcode: "linuxcnc/gcode/custom-fixture.ngc",
|
||||
},
|
||||
},
|
||||
);
|
||||
assert.throws(
|
||||
() => createMachineSessionSnapshotPayload("bad-machine", { gcodeFilename: "../escape.ngc" }),
|
||||
/Invalid G-code filename/,
|
||||
);
|
||||
const snapshot = createSessionSnapshot("session-1", snapshotPayload, {
|
||||
createdAt: "2026-06-08T00:00:00.000Z",
|
||||
metadata: { source: "node-smoke" },
|
||||
|
||||
Reference in New Issue
Block a user