diff --git a/sandbox/hermes-bridge b/sandbox/hermes-bridge index 7173035..be48368 100755 --- a/sandbox/hermes-bridge +++ b/sandbox/hermes-bridge @@ -17,45 +17,65 @@ shift HERMES_HOME="${HERMES_HOME:-$HOME/.hermes}" API_SOCKET="$HERMES_HOME/coredesktop-api.sock" -# Ask the gateway, through its control socket, where its API listens; prints -# the port, or nothing if no gateway is ready -api_port() { - local control="$HERMES_HOME/gateway.sock" origin +# The gateway's answer to `identify` on its control socket, or nothing if no +# gateway is running +identify() { + local control="$HERMES_HOME/gateway.sock" [ -S "$control" ] || control="$(cat "$HERMES_HOME/gateway.sock.path" 2> /dev/null)" [ -S "$control" ] || return 1 - origin="$(printf '{"protocol":1,"verb":"identify","id":1}\n' \ - | socat -t 5 - "UNIX-CONNECT:$control" 2> /dev/null \ - | jq -r 'select(.result.state == "ready") | .result.api_origin // empty' 2> /dev/null)" - # Only an IPv4 loopback origin is relayed, which is what Hermes uses by default + printf '{"protocol":1,"verb":"identify","id":1}\n' \ + | socat -t 5 - "UNIX-CONNECT:$control" 2> /dev/null | grep . +} + +# The port the gateway's API listens on, once the gateway is ready. Only an +# IPv4 loopback origin is relayed, which is what Hermes uses by default. +api_port() { + local origin + origin="$(identify | jq -r 'select(.result.state == "ready") | .result.api_origin // empty' 2> /dev/null)" [[ "$origin" =~ ^http://127\.0\.0\.1:([0-9]+)$ ]] || return 1 echo "${BASH_REMATCH[1]}" } if [ "$1" = "gateway" ] && [ "$2" = "run" ]; then + # A terminal finds no relay, rather than the last gateway's, until this one + # is up + rm -f "$API_SOCKET" # The relay waits for the gateway, which runs in this process once exec'd; # the sandbox ends both together ( - for _ in $(seq 120); do + for _ in $(seq 480); do if port="$(api_port)"; then exec socat "UNIX-LISTEN:$API_SOCKET,unlink-early,mode=600,fork" "TCP:127.0.0.1:$port" fi - sleep 1 + sleep 0.25 done echo "hermes-bridge: the gateway's API didn't come up; terminals can't reach it" >&2 ) & exec "$real" "$@" fi -# A terminal: relay the gateway's port, if a gateway is running. Without one, -# hermes starts its own gateway inside this sandbox, which needs no relay. -if [ -S "$API_SOCKET" ] && port="$(api_port)"; then - socat "TCP-LISTEN:$port,bind=127.0.0.1,reuseaddr,fork" "UNIX-CONNECT:$API_SOCKET" & - # Wait for the listener (state 0A, LISTEN, in /proc/net/tcp) so hermes' - # first connection doesn't fail - hex="$(printf ':%04X ' "$port")" - for _ in $(seq 50); do - grep -q "$hex.* 0A " /proc/net/tcp && break - sleep 0.05 +# A terminal: relay the gateway's port, if a gateway is running or its service +# is turned on, waiting for one that is still starting. Without one, hermes +# starts its own gateway inside this sandbox, which needs no relay. +if [ -e "$HOME/.config/systemd/user/default.target.wants/hermes-gateway.service" ] \ + || identify > /dev/null; then + [ -S "$API_SOCKET" ] && api_port > /dev/null || echo "Waiting for Hermes' gateway..." >&2 + for _ in $(seq 240); do + [ -S "$API_SOCKET" ] && port="$(api_port)" && break + port="" + sleep 0.25 done + if [ -n "$port" ]; then + socat "TCP-LISTEN:$port,bind=127.0.0.1,reuseaddr,fork" "UNIX-CONNECT:$API_SOCKET" & + # Wait for the listener (state 0A, LISTEN, in /proc/net/tcp) so hermes' + # first connection doesn't fail + hex="$(printf ':%04X ' "$port")" + for _ in $(seq 50); do + grep -q "$hex.* 0A " /proc/net/tcp && break + sleep 0.05 + done + else + echo "hermes-bridge: Hermes' gateway is running but its API isn't reachable; try: systemctl --user restart hermes-gateway" >&2 + fi fi exec "$real" "$@"