Skip to content

Instantly share code, notes, and snippets.

@guest271314
Last active September 3, 2024 03:29
Show Gist options
  • Save guest271314/9d08a9b55e41fc6a4d8e71b7092a148b to your computer and use it in GitHub Desktop.
Save guest271314/9d08a9b55e41fc6a4d8e71b7092a148b to your computer and use it in GitHub Desktop.
Golfing a Native Messaging host with tee command

I was experimenting earlier today with using Meta's shermes and hermes as a Native Messaging host.

That experiment metamorphisized into using Chrome browser as a Native Messaging host.

Before I proceed this is what the Native Messaging protocol is

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.

A host is a shell script, progam, application, whatever you use to implement that protocol.

I never got shermes or hermes to write to standard output. But along the way I started using tee to write standard input to a file and then get that file from the file system using Web extension code, since we can fetch() chrome-extension: (or file: with "<all_urls>" or "file:///*" in "host_permissions") protocol using an extension on Chromium.

The code originally was something like

chrome.runtime.sendNativeMessage(
      "nm_hermes",
  {0:[...Array(209713), 111]}
    ).then((message) => {
  console.log(JSON.stringify(message).length, message);
    }).then((message) => {
  if (message) {
    console.log({message});
    return;
  }
fetch("./input.txt")
  .then((r) => r.arrayBuffer())
  .then(async (ab) => {
    console.log(ab);
    var u32 = new Uint32Array(ab.slice(0, 4));
    var u8 = await new Response(ab.slice(4)).json();
    console.log(u32, u8)
  })}).catch(console.error);

And in the shell script I was originally doing this

#/bin/bash
cp /dev/stdin input.txt

which lead to

args="$*"
echo "$args" > args.txt
tee input.txt
sleep 1
rm -rf ./input.txt

and eventually

#!/bin/bash
tee

then just

#!/usr/bin/tee -a

The briefest code as a shell script I have observed in the wild for this task is from Native message chrome extension is only executed when I reload the extension

#!/usr/bin/env bash
stdin=$(cat)
s=$(echo $stdin | tail -c +2)
echo $s | rofi -dmenu

I wound up using Busybox's tee due to less RSS compared to GNU Coreutils. This just echoes input from the browser back to the browser. Nothing special, besides the minimal size of code to do that compared to hosts written in shell scripts.

#!/usr/bin/env -S busybox tee -a

I didn't start the day trying to golf anything. Just happened that way. So I figured I'd share.

Sometimes when you're programming to achieve one goal, you might wind up doing something else along the way that happens to be fun, or just interesting to yourself.

Happy hacking. Cheers.

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