Skip to content

nime: keep the Node.js backend alive on uninitialized clients and malformed lines (#936, #937) - #971

Open
ilwu wants to merge 3 commits into
EasyIME:masterfrom
ilwu:fix-nime-uninitialized-client
Open

ilwu wants to merge 3 commits into
EasyIME:masterfrom
ilwu:fix-nime-uninitialized-client

Conversation

@ilwu

@ilwu ilwu commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Complements #945/#946/#955: those cover the createServer callback 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 — its init named an unknown GUID, or it never sent init (a client that outlives a backend restart). Previously handleRequest() dereferenced null and the TypeError killed the process.
  • The stdin line handler wraps 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 test in node/ runs it. Against the previous nimeServer.js 4 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.js directly; the normal meow init → onActivate → filterKeyDown path is unchanged.

Generated with assistance from Claude Code (Claude Fable 5.1).

🤖 Generated with Claude Code

ilwu and others added 3 commits October 19, 2026 21:33
…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>
asdf80730 added a commit to asdf80730/PIME that referenced this pull request Oct 20, 2026
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.
@asdf80730

asdf80730 commented Oct 20, 2026 •

Copy link
Copy Markdown

Verified on node v24: node --test tests/nimeServer.test.js → 5/5 pass. I also re-ran the crash scenarios against 1458cea and against this branch:

  • unknown GUID init, then onActivate: 1458cea exits; here both replies are success:false and the process stays alive.
  • no init, then onActivate: 1458cea exits; here {"success":false,"seqNum":0}.
  • malformed JSON line: 1458cea exits; here {"success":false} plus a stderr line.
  • payload containing |: 1458cea truncates at the pipe (split('|', 2)) and dies in JSON.parse; the indexOf split fixes it.

One thing to settle before merge: node/node_modules/nime is committed while package.json still pins nime: 0.5.0, so a future npm install or dependency bump silently drops this patch. Should the patch be documented next to the dependency, or should nime be vendored under a local path so the pin cannot overwrite it?

If this lands, the dummy service in #946 becomes redundant, so #946 could be dropped.

@PCMan PCMan assigned PCMan and jessy1092 and unassigned PCMan Oct 20, 2026
@PCMan

PCMan commented Oct 20, 2026

Copy link
Copy Markdown
Member

@jessy1092 could you help review nime server changes, please? Thank you!

@ilwu

ilwu commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for re-running it. On the pin question, what I found:

  • build.bat never runs npm install in node/ itself — only in McBopomofoWeb/McFoximWeb/McTabimWeb and node/input_methods/emojime. The installer packages node/ as it is in the tree, so a build does not overwrite the vendored copy. Someone running npm install in node/ by hand would, but with the hidden .package-lock.json matching 0.5.0 npm leaves the existing directory alone and does not re-extract it, so even that is unlikely to drop the patch.
  • The vendored copy already diverges from the npm package: nime@0.5.0 on the registry (and EasyIME/NIME master, last commit 2017) has no seqNum echo on close, which d0e4235 added here. So this PR follows the existing practice rather than starting it.

That said, I agree it is fragile. Two options, happy to do either:

  1. Send the same changes (this PR's two fixes plus the close reply from d0e4235) to EasyIME/NIME, publish 0.5.1, and bump the pin here. Cleanest, but needs @jessy1092's time for the release.
  2. Move the copy to a local path, e.g. node/vendor/nime, with "nime": "file:vendor/nime" in package.json, so the registry can never replace it and the divergence is explicit in the tree.

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))

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants