WebAssembly / wasi-cli

Command-Line Interface (CLI) World for WASI
60 stars 11 forks source link

Use cases: Read stdin to V8's d8 shell in a Native Messaging host #45

Open guest271314 opened 1 month ago

guest271314 commented 1 month ago

[Use case 1] [Provide example code snippets and diagrams explaining how the API would be used to solve the given problem]

Read standard input from Chromium or Firefox browsers to V8's d8 shell that is a Native Messaging host.

This is the Native Messaging protocol:

Native messaging protocol (Chrome Developers)

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.

This is why V8's d8's shell readline() function does not read "32-bit message length in native byte order" and proceed with reading the JSON content Implement reading STDIN to an ArrayBuffer. Precedent: writeFile("/proc/self/fd/1")

That's OK. As I told you before, d8 isn't trying to be a general-purpose shell; it's a tool for developing V8. If you want a V8-embedding shell that does more than d8 offers, find one or write your own.

What I'm currently doing with bash, which is really dash on the Linux machine I'm on

function getMessage(pid) {
  try {
    // readline() doesn't read past the Uint32Array equivalent message length
    // V8 authors are not interested in reading STDIN to an ArrayBuffer in d8
    // https://groups.google.com/g/v8-users/c/NsnStT6bx3Y/m/Yr_Z1FwgAQAJ
    // Use dd https://pubs.opengroup.org/onlinepubs/9699919799/utilities/dd.html
    // or GNU Coreutils head https://www.gnu.org/software/coreutils/manual/html_node/head-invocation.html
    // # length=$(head -q -z --bytes=4 /proc/${pid}/fd/0 | od -An -td4 -)
    // # message=$(head -q -z --bytes=$((length)) /proc/${pid}/fd/0)
    // to get message length and return message from Bash script
    const stdin = (os.system("bash", [
      "--posix",
      "-c",
      `
  length=$(dd iflag=fullblock oflag=nocache conv=notrunc,fdatasync bs=4 count=1 if=/proc/${pid}/fd/0 | od -An -td4 -)
  message=$(dd iflag=fullblock oflag=nocache conv=notrunc,fdatasync bs=$((length)) count=1 if=/proc/${pid}/fd/0)
  echo "$message"`,
    ])).trim();
    if (stdin != undefined && stdin != null && stdin.length) {
      const message = encodeMessage(stdin.trim());
      // https://stackoverflow.com/a/58288413
      // const header = new Uint32Array([
      //  ((uint32) =>
      //    (uint32[3] << 24) |
      //    (uint32[2] << 16) |
      //    (uint32[1] << 8) |
      //    (uint32[0]))(Array.from({
      //    length: 4,
      //    }, (_, index) => (message.length >> (index * 8)) & 0xff)),
      // ]);
      // writeFile("messageLength.txt", encodeMessage(JSON.stringify(header)));
      return encodeMessage(stdin);
    } else {
      return;
    }
  } catch (e) {
    writeFile("getMessageError.txt", encodeMessage(e.message));
  }
}

Some prior art using WASI-SDK to compile C Native Messaging host to WASM and using wasmtime as the executable, https://github.com/guest271314/native-messaging-webassembly/blob/main/nm_c_wasm.sh, and WAT embedded in https://github.com/guest271314/native-messaging-webassembly/blob/main/nm_c_wat.sh.

Ideally this could be run using WebAssembly.compile() in a non-browser JavaScript engine shell or runtime environment; to read stardard input and write to standard output, without necessarily relying on an executable such as wasmtime, wasmer, or javy. Not sure if that is possible.

Just providing a use case for the placeholder. I've got some reading to do on "the Component Model wit language" to try to implement this in that format.