Repository navigation
cq-viewer 1.1.1: fix concurrent ~/.cqview writes and Python after dispose (review of #18) - #20
Merged
Merged
Conversation
… loopback-only routes Follow-up to the post-merge review of #18. Required: - Concurrent writes: temp files are named <file>.<pid>.<uuid>.tmp (two writes in the same millisecond collided before: 40 concurrent selection saves gave 27x 500), and the selection save joins the existing write queue with roots/scene/request writes. The temp file is removed on failure and takes the existing file's mode (docs/security.md). - dispose during STEP conversion: runChild refuses once disposed, so the fallback can no longer start a Python nobody cleans up. A conversion stopped by the time limit, by dispose, or killed with SIGKILL/SIGTERM fails without the fallback (worst case is now 1x300 s, not 2x). A native crash (SIGSEGV, SIGABRT ...) still tries the simpler fallback, which is what it is for. Watchers are not recreated after dispose, and dispose waits for a write already in progress. Optional suggestions, also done: - Every route (page included) refuses a non-loopback Host and an Origin other than this listener (DNS rebinding could register folders and read models before). - step-cache pruning on the first conversion after start: unused for 30 days, beyond 1 GB (LRU, a hit refreshes mtime), temp files older than a day; only its own files. - host-bridge APP_INFO and MCP serverInfo versions follow plugin.json (test checks). tests/server.test.mjs (9 tests, fake Python for the conversion paths); 19/19 plugin tests. npm run check: plugins/hanzijie/cq-viewer OK (0 errors, 0 warnings).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to @MyPrototypeWhat's post-merge review of #18 — thanks for the careful testing. Both required changes are fixed and the three optional suggestions are done too. Version 1.1.1.
Required
1. Concurrent writes to
~/.cqviewwriteJsonAtomicnames temp files<file>.<pid>.<randomUUID>.tmp, removes the temp file on failure, and gives it the existing file's mode before the rename (docs/security.md).serial()) asroots.json, the scene copy, and the request log. (addRoot's read-modify-write was already queued in 1.1.0 / cq-viewer 1.1.0: MCP tools to add model folders and files, bundled CadQuery skill #19, which is why the roots part of the report no longer reproduced onmain; the temp-name collision still did.)mainbefore the fix: 40 concurrentPOST /api/selection→ 27 × 500. After: 40 × 200; 8 concurrent folder registrations, page and MCP mixed → 8 × 200, all 8 inroots.json.2. No Python after
disposerunChildrejects withdisposedoncedispose()has run, and a child that exits because dispose killed it reportsdisposedtoo, so the fallback cannot start.SIGKILL/SIGTERM.SIGSEGV,SIGABRT, …) ofstep_mesh.pystill tries the simpler inline fallback, since that is the case the fallback exists for (the XCAF path crashing on a file that plainimportStephandles). Happy to drop that if you prefer the stricter rule.Optional suggestions
Hostthat is not127.0.0.1/localhost/::1, and anOriginthat is not this listener itself (loopback host and our port). Verified inside MiniMax Code: the page opened with?root=still reads and registers folders, and its SSE connection stays up (viewer_connected: true).host-bridge.jsAPP_INFOand the MCPserverInfofollowplugin.json(1.1.1); a test fails if they drift.Checks
npm run check:plugins/hanzijie/cq-viewer: OK— 0 errors, 0 warnings; 55/55 repo tests.node --test plugins/hanzijie/cq-viewer/tests/*.test.mjs: 19/19. Newtests/server.test.mjs(9 tests): concurrency (above); with a fakepythonviaCQVIEW_PYTHON: dispose mid-conversion killsstep_mesh.py(pid gone) and no fallback runs within 1.5 s, aSIGKILLed conversion returns 422 without fallback, aSIGSEGVone does fall back; cache pruning; 403 for foreign Host/Origin on the page, API, and MCP; version sync. The fake-Python tests are skipped on Windows.step_mesh.py(cqvm, 1.2 s) and the second request is a cache hit.Not verified
unlinkof a file being streamed is caught, but not exercised there).Need help on this PR? Tag
@codesmith-botwith what you need.