64 lines
3.8 KiB
JavaScript
64 lines
3.8 KiB
JavaScript
import { createServer } from "node:http";
|
|
import { readFile } from "node:fs/promises";
|
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
import { normalize, join } from "node:path";
|
|
import { tmpdir } from "node:os";
|
|
import { pathToFileURL } from "node:url";
|
|
|
|
const root = new URL("../web/", import.meta.url).pathname.replace(/\/$/, "");
|
|
const modulePath = process.env.PLAYWRIGHT_MODULE;
|
|
|
|
function blocked(code, reason = null) {
|
|
console.log(JSON.stringify({ schema: "browser-opfs-s6-07-crash-sample.v1", status: "blocked", browser: "chromium", code, reason }));
|
|
}
|
|
|
|
if (!modulePath) {
|
|
blocked("playwright_unavailable", "PLAYWRIGHT_MODULE is not set");
|
|
} else {
|
|
let server;
|
|
let firstContext;
|
|
let secondContext;
|
|
let browserServer;
|
|
const profile = await mkdtemp(join(tmpdir(), "linuxcnc-opfs-crash-s6-07-"));
|
|
try {
|
|
const imported = await import(pathToFileURL(modulePath).href);
|
|
const playwright = imported.default ?? imported;
|
|
server = createServer(async (request, response) => {
|
|
const requested = (request.url ?? "/").split("?")[0];
|
|
const relative = requested === "/" ? "/app/browser-opfs-probe.html" : requested;
|
|
const file = normalize(join(root, relative));
|
|
if (!file.startsWith(root + "/")) { response.writeHead(403); response.end(); return; }
|
|
try { const body = await readFile(file); response.writeHead(200, { "content-type": file.endsWith(".html") ? "text/html" : "text/javascript", "cache-control": "no-store" }); response.end(body); } catch { response.writeHead(404); response.end(); }
|
|
});
|
|
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
const port = server.address().port;
|
|
firstContext = await playwright.chromium.launchPersistentContext(profile, { headless: false });
|
|
browserServer = await firstContext.browser()._launchServer();
|
|
const writer = await firstContext.newPage();
|
|
await writer.goto(`http://127.0.0.1:${port}/app/browser-opfs-probe.html?mode=write&cleanup=false`);
|
|
await writer.waitForFunction(() => document.querySelector("#result")?.textContent !== "pending", null, { timeout: 10000 });
|
|
const written = JSON.parse(await writer.locator("#result").textContent());
|
|
if (written.status !== "verified") throw new Error(written.code ?? "opfs_write_blocked");
|
|
const processId = browserServer.process()?.pid ?? null;
|
|
if (!processId) throw new Error("browser_process_missing");
|
|
browserServer.kill();
|
|
await new Promise((resolve) => browserServer.once("close", resolve));
|
|
firstContext = null;
|
|
secondContext = await playwright.chromium.launchPersistentContext(profile, { headless: false });
|
|
const reader = await secondContext.newPage();
|
|
await reader.goto(`http://127.0.0.1:${port}/app/browser-opfs-probe.html?mode=read&cleanup=true`);
|
|
await reader.waitForFunction(() => document.querySelector("#result")?.textContent !== "pending", null, { timeout: 10000 });
|
|
const restored = JSON.parse(await reader.locator("#result").textContent());
|
|
if (restored.status !== "verified" || restored.content_hash !== written.content_hash || restored.cleanup !== true) throw new Error("opfs_crash_record_mismatch");
|
|
console.log(JSON.stringify({ schema: "browser-opfs-s6-07-crash-sample.v1", status: "verified", browser: "chromium", browser_version: (await secondContext.browser()).version(), mode: "process_kill_profile_reopen", process_killed: true, commit_seq: restored.commit_seq, content_hash: restored.content_hash, cleanup: restored.cleanup }));
|
|
} catch (error) {
|
|
blocked("opfs_crash_probe_failed", error?.message ?? error?.name ?? String(error));
|
|
} finally {
|
|
try { browserServer?.kill(); } catch {}
|
|
await secondContext?.close().catch(() => {});
|
|
await firstContext?.close().catch(() => {});
|
|
server?.close();
|
|
await rm(profile, { recursive: true, force: true });
|
|
}
|
|
}
|