Repository navigation
nime: keep the Node.js backend alive on uninitialized clients and malformed lines (#936, #937) - #971
Conversation
…ing (EasyIME#937) * handleClientRequest() replies {success: false, seqNum} when the client has no service, i.e. its init named an unknown GUID or it never sent init. nime creates a {service: null, state: null} entry for every new client id and hands the next request straight to handleRequest(), whose `service = textService` default does not apply to null. The resulting TypeError is uncaught and terminates the Node.js backend, taking every Node.js input method down. The TSF client always sends init first, but a client that outlives a backend restart hits this path. Generated with assistance from Claude Code (Claude Fable 5.1). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…hing (EasyIME#936) * Wrap JSON.parse() of the request payload in try/catch; a line that does not parse gets a {success: false} reply and an error on stderr. * Split the line on the first '|' only, so a payload containing '|' is no longer truncated before parsing. JSON.parse() throwing inside the stdin line handler was an uncaught exception, which terminates the Node.js backend and disables every Node.js input method until the launcher restarts it. Answering the bad line keeps the backend alive and lets the client fail fast instead of waiting for its RPC timeout. Generated with assistance from Claude Code (Claude Fable 5.1). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* tests/nimeServer.test.js drives server.js over stdin/stdout like PIMELauncher and checks the replies for a normal init, a client that never sent init, an init with an unknown GUID, a malformed line and a payload containing '|'. * `npm test` in node/ now runs it with the built-in node:test runner, so no extra dependency is needed. The two preceding fixes change how the backend reacts to bad input; these tests pin that behaviour down and fail against the previous nimeServer.js (4 of 5 cases). Generated with assistance from Claude Code (Claude Fable 5.1). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
EasyIME#961 is fixed via EasyIME#964; EasyIME#942 now has EasyIME#972; EasyIME#936/EasyIME#937 gained EasyIME#971, which patches the vendored nime. ARM64 installs register an ARM64X forwarder, so the architecture summary and installer card say so. Add the new EasyIME#966 issue and a short note on what moved upstream since 24e4dff.
|
Verified on node v24:
One thing to settle before merge: If this lands, the dummy service in #946 becomes redundant, so #946 could be dropped. |
|
@jessy1092 could you help review nime server changes, please? Thank you! |
|
Thanks for re-running it. On the pin question, what I found:
That said, I agree it is fragile. Two options, happy to do either:
I would not mix either into this PR, since it would turn a 2-file fix into a move; a follow-up PR seems better once you pick one. (Written with assistance from Claude Code (Claude Fable 5.1)) |
|
Very solid resilience improvement for #936 and #937. Splitting on (Review comment generated with assistance from Antigravity + Gemini 3.8 Flash) |
|
Note on repository boundaries: The fixes in Assigning @ottokang and @jessy1092 to review and coordinate the upstream fix. (Comment generated with assistance from Antigravity + Gemini 3.8 Flash) |
Upstream landed EasyIME#997/EasyIME#998 (launcher close forwarding and client-ID validation), EasyIME#988 (Python user-dir ACL fallback), EasyIME#971/EasyIME#951/EasyIME#937/EasyIME#936 (node guards and tests), EasyIME#996 (AGENTS.md AI declaration and header rules), and dropped the vendored inetc plugin in EasyIME#966. Conflict resolutions: - node/server.js: take upstream, which supersedes our EasyIME#937 implementation with an uncaughtException handler and the same fallback service. - node/loadServices.js: keep upstream's guards and re-thread the fork's `baseDir` parameter so test/loadServices.test.js still drives a fixture. - node/package.json: run upstream's nimeServer suite plus the two local suites, matching the CI steps. - PIMELauncher/src/protocol.rs: keep upstream's parse_backend_input and the rustfmt layout from local master. Generated with assistance from omp (DeepSeek V4.1 Flash).
Complements #945/#946/#955: those cover the
createServercallback and the top-level exception handler, but two paths inside nime itself still terminate the backend (details in my test comments on those PRs).handleClientRequest()answers{success: false, seqNum}when the client has no service — itsinitnamed an unknown GUID, or it never sentinit(a client that outlives a backend restart). PreviouslyhandleRequest()dereferencednulland theTypeErrorkilled the process.JSON.parse()in try/catch and answers{success: false}for a line it cannot parse, instead of throwing. It also splits on the first|only, so a payload containing|is no longer truncated (line.split('|', 2)drops the rest).node/tests/nimeServer.test.js(node:test, no new dependency) covers both fixes plus a baseline;npm testinnode/runs it. Against the previousnimeServer.js4 of the 5 cases fail.Keeping the backend alive matters because one bad request otherwise disables every Node.js input method until the launcher restarts the process, and the client that sent it waits for its RPC timeout instead of getting an answer.
Verified on Windows 11 with node v24 (and the bundled node 22) by driving
server.jsdirectly; the normal meowinit→onActivate→filterKeyDownpath is unchanged.Generated with assistance from Claude Code (Claude Fable 5.1).
🤖 Generated with Claude Code