推进 INI 面板会话恢复加载流程
This commit is contained in:
65
text10.txt
65
text10.txt
@@ -546,3 +546,68 @@ host_wasm_opfs_browser_smokes=ok
|
|||||||
`Restore And Load Session`:先校验 snapshot,再把 OPFS INI/parameter/tool-table 加载到
|
`Restore And Load Session`:先校验 snapshot,再把 OPFS INI/parameter/tool-table 加载到
|
||||||
interpreter WASM FS,并保持 G-code path 可运行。范围仍限定 OPFS/session/UI 编排,不
|
interpreter WASM FS,并保持 G-code path 可运行。范围仍限定 OPFS/session/UI 编排,不
|
||||||
解析或改写任何 CNC 语义。
|
解析或改写任何 CNC 语义。
|
||||||
|
|
||||||
|
六、2026-06-14 继续执行记录:INI panel restore-and-load session workflow
|
||||||
|
|
||||||
|
本轮继续推进 browser/UI workflow 的实质能力,把 snapshot restore 和 machine-session
|
||||||
|
load 串成一个可直接执行的入口。
|
||||||
|
|
||||||
|
完成内容:
|
||||||
|
|
||||||
|
- 在 `wasm-port/runtime/ui/ini-panel/app.js` 抽出
|
||||||
|
`restoreSessionSnapshotToEditor()`,统一执行 checked snapshot load、OPFS machine
|
||||||
|
file restore、编辑器回填和 snapshot 文件清单字段回填;
|
||||||
|
- 抽出 `loadMachineSessionIntoWasm()`,统一通过既有
|
||||||
|
`loadMachineSessionFromOpfs(...)` 把 OPFS INI、parameter、tool-table 加载到
|
||||||
|
interpreter WASM FS;
|
||||||
|
- 保留既有 `Restore Session Snapshot` 与 `Load Machine Session` 按钮行为,并让它们
|
||||||
|
复用上述 workflow helper;
|
||||||
|
- 新增 `Restore And Load Session` 控件:
|
||||||
|
- 先通过 `loadMachineSessionSnapshot(...)` 校验 snapshot;
|
||||||
|
- 再恢复 OPFS machine files 到编辑器;
|
||||||
|
- 再把 INI、parameter、tool-table 加载到 interpreter WASM FS;
|
||||||
|
- 保留 snapshot G-code path,供后续 `Run G-code` 使用;
|
||||||
|
- 在 browser INI panel smoke 中改为通过 `Restore And Load Session` 完成 session
|
||||||
|
恢复加载,再继续执行 G-code run,验证 snapshot path、OPFS file mapping、
|
||||||
|
LinuxCNC parameter/tool-table load result 和 canonical-event flow;
|
||||||
|
- 未改变 LinuxCNC INI parser、interpreter、parameter restore/save、tool-table load/save
|
||||||
|
或 G-code 执行语义;
|
||||||
|
- 未改变 OPFS path model、generic snapshot envelope、file-service、machine-session
|
||||||
|
bridge 或 LinuxCNC-owned runtime semantics。
|
||||||
|
|
||||||
|
验证已通过:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git diff --check
|
||||||
|
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh
|
||||||
|
wasm-port/tests/opfs/node/verify_file_service.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
|
||||||
|
SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_interp_browser.sh
|
||||||
|
wasm-port/tests/host/verify_host_smokes.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
关键输出:
|
||||||
|
|
||||||
|
```text
|
||||||
|
browser_ini_opfs_smoke=ok
|
||||||
|
opfs_file_service_node_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
|
||||||
|
```
|
||||||
|
|
||||||
|
下一步建议:
|
||||||
|
|
||||||
|
继续沿 UI workflow 做实质推进。优先把 `Run G-code` 的输入从固定
|
||||||
|
`GCODE_FILENAME` 收敛为“优先使用已恢复 snapshot 中的 G-code OPFS path,否则回退默认
|
||||||
|
G-code”,并在 browser smoke 中验证 restore-and-load 后运行的程序来自 snapshot 文件清单。
|
||||||
|
仍只做 OPFS/session/UI 编排,不解析或改写 G-code 语义。
|
||||||
|
|||||||
@@ -310,6 +310,37 @@ function syncEditorToWasmFs() {
|
|||||||
requireIniSdk().writeTextFile(WASM_FILE, editor.value);
|
requireIniSdk().writeTextFile(WASM_FILE, editor.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function restoreSessionSnapshotToEditor() {
|
||||||
|
const snapshot = await loadMachineSessionSnapshot(
|
||||||
|
SESSION_SNAPSHOT_ID,
|
||||||
|
MACHINE_ID,
|
||||||
|
{ filename: SESSION_SNAPSHOT_FILENAME },
|
||||||
|
);
|
||||||
|
const files = await loadMachineTextFiles(MACHINE_ID);
|
||||||
|
editor.value = files.ini;
|
||||||
|
setField("sessionIni", snapshot.payload.files.ini);
|
||||||
|
setField("sessionParameters", snapshot.payload.files.parameters);
|
||||||
|
setField("sessionToolTable", snapshot.payload.files.toolTable);
|
||||||
|
setField("sessionGcode", snapshot.payload.files.gcode);
|
||||||
|
setField("sessionSnapshot", `${snapshot.sessionId}/${SESSION_SNAPSHOT_FILENAME}`);
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadMachineSessionIntoWasm() {
|
||||||
|
loadedSession = await loadMachineSessionFromOpfs(
|
||||||
|
requireInterpSdk(),
|
||||||
|
MACHINE_ID,
|
||||||
|
{
|
||||||
|
...SESSION_WASM_FILES,
|
||||||
|
iniSdk: requireIniSdk(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
setField("sessionIni", loadedSession.ini.wasmPath);
|
||||||
|
setField("sessionParameters", loadedSession.parameters.wasmPath);
|
||||||
|
setField("sessionToolTable", loadedSession.toolTable.wasmPath);
|
||||||
|
return loadedSession;
|
||||||
|
}
|
||||||
|
|
||||||
async function loadSample() {
|
async function loadSample() {
|
||||||
setLog(`Fetching ${SAMPLE_PATH}`);
|
setLog(`Fetching ${SAMPLE_PATH}`);
|
||||||
const response = await fetch(SAMPLE_PATH);
|
const response = await fetch(SAMPLE_PATH);
|
||||||
@@ -463,18 +494,7 @@ document.getElementById("save-session-snapshot").addEventListener("click", async
|
|||||||
|
|
||||||
document.getElementById("restore-session-snapshot").addEventListener("click", async () => {
|
document.getElementById("restore-session-snapshot").addEventListener("click", async () => {
|
||||||
try {
|
try {
|
||||||
const snapshot = await loadMachineSessionSnapshot(
|
const snapshot = await restoreSessionSnapshotToEditor();
|
||||||
SESSION_SNAPSHOT_ID,
|
|
||||||
MACHINE_ID,
|
|
||||||
{ filename: SESSION_SNAPSHOT_FILENAME },
|
|
||||||
);
|
|
||||||
const files = await loadMachineTextFiles(MACHINE_ID);
|
|
||||||
editor.value = files.ini;
|
|
||||||
setField("sessionIni", snapshot.payload.files.ini);
|
|
||||||
setField("sessionParameters", snapshot.payload.files.parameters);
|
|
||||||
setField("sessionToolTable", snapshot.payload.files.toolTable);
|
|
||||||
setField("sessionGcode", snapshot.payload.files.gcode);
|
|
||||||
setField("sessionSnapshot", `${snapshot.sessionId}/${SESSION_SNAPSHOT_FILENAME}`);
|
|
||||||
setLog(
|
setLog(
|
||||||
[
|
[
|
||||||
"Restored machine session snapshot from OPFS.",
|
"Restored machine session snapshot from OPFS.",
|
||||||
@@ -492,17 +512,7 @@ document.getElementById("restore-session-snapshot").addEventListener("click", as
|
|||||||
|
|
||||||
document.getElementById("load-session").addEventListener("click", async () => {
|
document.getElementById("load-session").addEventListener("click", async () => {
|
||||||
try {
|
try {
|
||||||
loadedSession = await loadMachineSessionFromOpfs(
|
await loadMachineSessionIntoWasm();
|
||||||
requireInterpSdk(),
|
|
||||||
MACHINE_ID,
|
|
||||||
{
|
|
||||||
...SESSION_WASM_FILES,
|
|
||||||
iniSdk: requireIniSdk(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
setField("sessionIni", loadedSession.ini.wasmPath);
|
|
||||||
setField("sessionParameters", loadedSession.parameters.wasmPath);
|
|
||||||
setField("sessionToolTable", loadedSession.toolTable.wasmPath);
|
|
||||||
setLog(
|
setLog(
|
||||||
[
|
[
|
||||||
"Loaded machine session into the interpreter WASM filesystem.",
|
"Loaded machine session into the interpreter WASM filesystem.",
|
||||||
@@ -518,6 +528,28 @@ document.getElementById("load-session").addEventListener("click", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById("restore-load-session").addEventListener("click", async () => {
|
||||||
|
try {
|
||||||
|
const snapshot = await restoreSessionSnapshotToEditor();
|
||||||
|
await loadMachineSessionIntoWasm();
|
||||||
|
setField("sessionGcode", snapshot.payload.files.gcode);
|
||||||
|
setLog(
|
||||||
|
[
|
||||||
|
"Restored and loaded machine session snapshot.",
|
||||||
|
`Snapshot: ${snapshot.sessionId}/${SESSION_SNAPSHOT_FILENAME}`,
|
||||||
|
`INI: ${loadedSession.ini.opfsPath} -> ${loadedSession.ini.wasmPath}`,
|
||||||
|
`Parameter file: ${loadedSession.parameters.opfsPath} -> ${loadedSession.parameters.wasmPath}`,
|
||||||
|
`Parameters: ${loadedSession.parameters.result.trim()}`,
|
||||||
|
`Tool table file: ${loadedSession.toolTable.opfsPath} -> ${loadedSession.toolTable.wasmPath}`,
|
||||||
|
`Tool table: ${loadedSession.toolTable.result.trim()}`,
|
||||||
|
`G-code: ${snapshot.payload.files.gcode ?? "-"}`,
|
||||||
|
].join("\n"),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
setLog(`Machine session snapshot restore/load failed: ${error.message}`, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
document.getElementById("run-gcode").addEventListener("click", async () => {
|
document.getElementById("run-gcode").addEventListener("click", async () => {
|
||||||
try {
|
try {
|
||||||
if (!loadedSession) {
|
if (!loadedSession) {
|
||||||
|
|||||||
@@ -230,6 +230,7 @@
|
|||||||
<button id="load-machine-files">Load Machine Files</button>
|
<button id="load-machine-files">Load Machine Files</button>
|
||||||
<button id="save-session-snapshot">Save Session Snapshot</button>
|
<button id="save-session-snapshot">Save Session Snapshot</button>
|
||||||
<button id="restore-session-snapshot">Restore Session Snapshot</button>
|
<button id="restore-session-snapshot">Restore Session Snapshot</button>
|
||||||
|
<button id="restore-load-session" class="secondary">Restore And Load Session</button>
|
||||||
<button id="sync-wasm">Sync To WASM FS</button>
|
<button id="sync-wasm">Sync To WASM FS</button>
|
||||||
<button id="query" class="secondary">Query LinuxCNC Fields</button>
|
<button id="query" class="secondary">Query LinuxCNC Fields</button>
|
||||||
<button id="load-session" class="secondary">Load Machine Session</button>
|
<button id="load-session" class="secondary">Load Machine Session</button>
|
||||||
|
|||||||
@@ -413,10 +413,10 @@ TOOL_TABLE = browser-tool.tbl
|
|||||||
if (!uiDocument.getElementById("ini-editor").value.includes("MACHINE = browser-smoke")) {
|
if (!uiDocument.getElementById("ini-editor").value.includes("MACHINE = browser-smoke")) {
|
||||||
throw new Error("UI restored session snapshot did not reload INI text");
|
throw new Error("UI restored session snapshot did not reload INI text");
|
||||||
}
|
}
|
||||||
uiDocument.getElementById("load-session").click();
|
uiDocument.getElementById("restore-load-session").click();
|
||||||
await waitFor(
|
await waitFor(
|
||||||
() => uiDocument.getElementById("log")?.textContent.includes("Loaded machine session"),
|
() => uiDocument.getElementById("log")?.textContent.includes("Restored and loaded machine session"),
|
||||||
"machine session load",
|
"restore and load machine session",
|
||||||
);
|
);
|
||||||
assertEqual(
|
assertEqual(
|
||||||
uiDocument.getElementById("field-session-ini").textContent,
|
uiDocument.getElementById("field-session-ini").textContent,
|
||||||
@@ -435,9 +435,10 @@ TOOL_TABLE = browser-tool.tbl
|
|||||||
);
|
);
|
||||||
const uiLog = uiDocument.getElementById("log").textContent;
|
const uiLog = uiDocument.getElementById("log").textContent;
|
||||||
if (!uiLog.includes("restore_parameters=0") || !uiLog.includes("tooldata_load=0")) {
|
if (!uiLog.includes("restore_parameters=0") || !uiLog.includes("tooldata_load=0")) {
|
||||||
throw new Error(`UI session log missing LinuxCNC load result: ${uiLog}`);
|
throw new Error(`UI restore/load session log missing LinuxCNC load result: ${uiLog}`);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
|
!uiLog.includes("Snapshot: ui-machine-session/ui-machine-session.json") ||
|
||||||
!uiLog.includes(
|
!uiLog.includes(
|
||||||
"Parameter file: linuxcnc/machines/xyzab-tdr/linuxcnc.var -> /work/session-linuxcnc.var",
|
"Parameter file: linuxcnc/machines/xyzab-tdr/linuxcnc.var -> /work/session-linuxcnc.var",
|
||||||
) ||
|
) ||
|
||||||
@@ -445,7 +446,7 @@ TOOL_TABLE = browser-tool.tbl
|
|||||||
"Tool table file: linuxcnc/machines/xyzab-tdr/tool.tbl -> /work/session-tool.tbl",
|
"Tool table file: linuxcnc/machines/xyzab-tdr/tool.tbl -> /work/session-tool.tbl",
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
throw new Error(`UI session log missing OPFS default file mapping: ${uiLog}`);
|
throw new Error(`UI restore/load session log missing OPFS default file mapping: ${uiLog}`);
|
||||||
}
|
}
|
||||||
uiDocument.getElementById("run-gcode").click();
|
uiDocument.getElementById("run-gcode").click();
|
||||||
await waitFor(
|
await waitFor(
|
||||||
|
|||||||
Reference in New Issue
Block a user