0
\$\begingroup\$

Native Messaging host using Mozilla SpiderMonkey JavaScript/WebAssembly engine.

Documentations

Native messaging protocol (Chrome Developers)

In pertinent part

Chrome starts each native messaging host in a separate process and communicates with it using standard input (stdin) and standard output (stdout). The same format is used to send messages in both directions; each message is serialized using JSON, UTF-8 encoded and is preceded with 32-bit message length in native byte order. The maximum size of a single message from the native messaging host is 1 MB, mainly to protect Chrome from misbehaving native applications. The maximum size of the message sent to the native messaging host is 4 GB.

Some development background Why is this SpiderMonkey Native Messsaging host not sending stdout to the client?.

ECMA-262 does not specify reading stdin or writing to stdout for JavaScript. At the JavaScript engine level what that means is that a JavaScript engine can, or cannot have I/O implemented and still be perfectly ECMA-262 test conformant. QuickJS includes a way to read stdin and write to stdout. Mozilla SpiderMonkey is little trickier.

  • I have to send an additional "\r\n\r\n" message from the client (browser) to the host (native application) for the host to get the message. So where in other languages and engines I can just send port.postMessage(new Array(209715)), with SpiderMonkey I have to also send and additional message at the end of every message I send port.postMessage("\r\n\r\n").
  • Don't ask me to explain those regular expressions. I read the string that gets to the host and kept creating regular expressions, line-by-line, until I got what I was expecting.
  • Using /proc/self/fd/1 is not ideal, as Apple OS's don't have that, and neither do Microsoft OS's; works on Debian and Ubuntu Linux operating systems.

Note, an Array with 209715 length in JavaScript winds up being 1 MB serialized to JSON, accounting for the null value set at indexes 0-209714.

Here's the working code

#!/usr/bin/env -S JS_STDERR=err.txt /home/user/.esvu/engines/jsshell/js
// SpiderMonkey Shell Native Messaging host (W.I.P.)
// guest271314 7-7-2023, 6-16-2024
function encodeMessage(str) {
  return new Uint8Array([...str].map((s) => s.codePointAt()));
}
// Call readline() N times to catch `\r\n\r\n"` from 2d port.postMessage()
let done = false;

let reads = 0;

function getMessage() {
  let stdin;
  while (true) {
    stdin = readline();
    if (stdin !== null) {
      break;
    }
  }

  let data = `${stdin}`.replace(/[\r\n]+|\\x([0-9A-Fa-f]{2,4})/gu, "")
    .replace(/[^A-Za-z0-9\s\[,\]\{\}:_"]+/igu, "")
    .replace(/^"rnrn/gu, "")
    .replace(/^[#\r\n\}_]+(?=\[)/gu, "")
    .replace(/^"(?=["\{]+)|^"(?!"$)/gu, "")
    .replace(/^\[(?=\[(?!.*\]{2}$))/gu, "")
    .replace(/^\{(?!\}|.+\}$)/gu, "")
    .replace(/^[0-9A-Z]+(?=[\[\{"])/igu, "")
    .replace(/^[\]\}](?=\[)/i, "")
    .trimStart().trim();

  return encodeMessage(data);
}

function sendMessage(message) {
  os.file.writeTypedArrayToFile(
    "/proc/self/fd/1",
    new Uint32Array([message.length]),
  );
  os.file.writeTypedArrayToFile("/proc/self/fd/1", message);
}

function main() {
  while (true) {
    const message = getMessage();
    sendMessage(message);
  }
}

try {
  main();
} catch (e) {
  os.file.writeTypedArrayToFile(
    "caught.txt",
    encodeMessage(JSON.stringify(e.message)),
  );
  quit();
}

\$\endgroup\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.