The steps to reproduce everything I describe above are here https://github.com/guest271314/native-messaging-spidermonkey-shell. Specially here https://github.com/guest271314/native-messaging-spidermonkey-shell/blob/main/nm_spidermonkey.js.
os.system(`pgrep -f "${scriptArgs[0]}"`);
results in js
exiting with an error
Error when communicating with the native messaging host.
There’s no terminal or TTY. I’m experimenting and testing SpiderMonkey as a Native Messaging host.
This is the protocol and working examples in C, C++, Python, Node.js, Deno, Bun, QuickJS, txiki.js, WebAssembly/WASI, Bash, nm_host
is JavaScript runtime agnostic tested the same code using node
, deno
, bun
, https://github.com/guest271314/NativeMessagingHosts?tab=readme-ov-file#native-messaging-documentation.
This is my local testing code, heavily commented. I started testing V8 and SpiderMonkey as Native Messaging hosts around a year ago. Precisely because I knew it would be challenging due to lack of standard input/outout/error streams in JavaScript. There’s zero compatibility or interoperability as to reading STDIN or writing to STDOUT for JavaScript(/WebAssembly) engines and runtimes.
#!/usr/bin/env -S JS_STDERR=err.txt /home/user/.jsvu/engines/spidermonkey/spidermonkey --enable-import-assertions --enable-uint8array-base64 --enable-arraybuffer-resizable --enable-top-level-await
// /home/user/.jsvu/engines/spidermonkey/spidermonkey
// 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()
function getMessage() {
let stdin;
while (true) {
stdin = readline();
//const previous = redirect(`${reads++}.txt`);
//putstr(stdin);
//redirect(previous);
if (stdin !== null) {
break;
}
}
// \\x([0-9A-Fa-f]{2,4})|\d+\\x([0-9A-Fa-f]{2,4})|^\r\n\r\n
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, "") // |^"(?!"$) // sendMessage("{}"):{}"
.replace(/^\[(?=\[(?!.*\]{2}$))/gu, "")
.replace(/^\{(?!\}|.+\}$)/gu, "")
.replace(/^[0-9A-Z]+(?=[\[\{"])/igu, "") // [^A-Za-z0-9\s\[,\]\{\}:_"]
.replace(/^[\]\}](?=\[)/i, "")
.trimStart().trim();
//if (/^\[\[/u.test(d) && !/\]\]$/.test(d)
// || (/^\{/u.test(d) && !/\}$/u.test(d))
// || (/^\[\[/u.test(d) && !/\]\]/u.test(d))
//) {
//d = d.slice(1)
//}
//if (d[0] === `###"\r\n\r\n"####`) d = d.slice(1)
//let previous = redirect("length.txt");
//putstr(data.length);
//redirect(previous); // restore the redirection to stdout
os.file.writeTypedArrayToFile("input.txt", encodeMessage(data));
// putstr(d);
return encodeMessage(data);
//const re = redirect(`${reads++}.txt`);
//putstr(`${stdin}`);
//redirect(re); // restore the redirection to stdout
/*
const data = encodeMessage(stdin.replace(/\r\n+/g, ``)); // new Uint8Array([...stdin].map((s) => s.codePointAt()));
const view = new DataView(data.buffer);
const length = view.getUint32(0, true);
const message = data.subarray(4);
//if (done) {
// return void 0;
//}
// if (!done) {
// https://stackoverflow.com/a/52434176
const previous = redirect("length.txt");
putstr(`${length}`);
redirect(previous); // restore the redirection to stdout
os.file.writeTypedArrayToFile("input.txt", message);
// done = true;
return message;
//}
*/
}
function sendMessage(message) {
os.file.writeTypedArrayToFile(
"/proc/self/fd/1",
new Uint32Array([message.length]),
);
os.file.writeTypedArrayToFile("/proc/self/fd/1", message);
// os.file.close("/proc/self/fd/1");
}
function main() {
// Send help() to client
// const previous = redirect("help.txt");
// putstr(help());
// redirect(previous); // restore the redirection to stdout
// const h = read("help.txt", "binary");
// sendMessage(encodeMessage(JSON.stringify([...h])));
// TODO: Make this persistent, comparable to JavaScript runtimes
// sendMessage(encodeMessage(JSON.stringify("TEST")));
//const file = os.file.readFile("help.txt");
//sendMessage(encodeMessage(file));
const pid = os.getpid();
//const ppid = os.system("pgrep", ["-f", "chrome"]); // 3035687
//os.file.writeTypedArrayToFile("ppid.txt", encodeMessage(JSON.stringify(ppid)));
//if (ppid == 512) sendMessage(encodeMessage(JSON.stringify("yup")));
sendMessage(encodeMessage(JSON.stringify({pid})));
sendMessage(encodeMessage(JSON.stringify({scriptPath, scriptArgs})));
while (true) {
// \x00 or \x01, 512 or 513
const client = os.system("pgrep", ["-f", scriptArgs[0]]);
if (client & 0xff === 1) {
os.file.writeTypedArrayToFile("exit.txt", encodeMessage(JSON.stringify(client & 0xff)));
break;
}
const message = getMessage();
sendMessage(message);
}
}
try {
main();
} catch (e) {
os.file.writeTypedArrayToFile(
"caught.txt",
encodeMessage(JSON.stringify(e.message)),
);
quit();
}