infra/remote-chromium.sh
Tommy Rantti e24bd035fd Give waypipe a digit-led socket name so snap Chromium can open it
Snap Chromium's AppArmor profile only allows /run/user/*/wayland-[0-9]*;
waypipe's default random name starts with a letter and was refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 14:28:11 +03:00

78 lines
3.3 KiB
Bash
Executable file

#!/usr/bin/env bash
# Run on the travel laptop: closes any Chromium running for you on the remote
# machine (Chromium allows one process per profile, so a running instance
# would swallow the new window), then launches it there with its window
# drawn here. Its audio is forwarded here too (needs pactl on both ends).
#
# Usage: remote-chromium.sh [--x11] [host]
# --x11 classic X11 forwarding instead of waypipe
# host ssh host to run Chromium on (default: teemu-thinkpad-ubuntu)
set -euo pipefail
MODE="waypipe"
HOST="teemu-thinkpad-ubuntu"
for arg in "$@"; do
case "$arg" in
--x11) MODE="x11" ;;
-*) echo "Unknown option: $arg"; exit 1 ;;
*) HOST="$arg" ;;
esac
done
if [ "$MODE" = "waypipe" ] && ! command -v waypipe >/dev/null 2>&1; then
echo "waypipe not installed here - run: sudo apt install waypipe (needed on both machines)"
exit 1
fi
ssh "$HOST" bash -s <<'EOF'
# snap build (Ubuntu) and the Debian package - matches the browser binary only,
# not shells/editors that merely mention "chromium"
PAT='chromium-browser/chrome|/usr/lib/chromium/chromium'
if pgrep -u "$USER" -f "$PAT" >/dev/null; then
echo "Chromium is running on $(hostname) - closing it gracefully..."
pkill -TERM -u "$USER" -f "$PAT"
for _ in $(seq 1 10); do
pgrep -u "$USER" -f "$PAT" >/dev/null || break
sleep 1
done
if pgrep -u "$USER" -f "$PAT" >/dev/null; then
echo "Still running after 10s - force killing."
pkill -KILL -u "$USER" -f "$PAT"
fi
fi
EOF
# Audio: Chromium plays through the remote's audio system, so give that system
# a virtual speaker that forwards over the tailnet to this machine, and point
# only this Chromium at it (PULSE_SINK). The snap sandbox rules out simply
# forwarding the audio socket over ssh. Both ends need pactl (pulseaudio-utils).
AUDIO_ENV=()
LOCAL_MOD="" REMOTE_MOD=""
SINK="chromium_to_$(hostname | tr -c 'a-zA-Z0-9\n' '_')"
if command -v pactl >/dev/null 2>&1 && ssh "$HOST" command -v pactl >/dev/null 2>&1; then
LOCAL_IP=$(tailscale ip -4)
REMOTE_IP=$(tailscale ip -4 "$HOST")
# unload leftovers from a run that didn't clean up, so reruns don't fail
pactl list short modules | awk -v ip="$LOCAL_IP" '/module-native-protocol-tcp/ && index($0, ip) {print $1}' | xargs -r -n1 pactl unload-module
ssh "$HOST" "pactl list short modules | awk '/module-tunnel-sink/ && /sink_name=$SINK/ {print \$1}' | xargs -r -n1 pactl unload-module"
LOCAL_MOD=$(pactl load-module module-native-protocol-tcp port=4713 listen="$LOCAL_IP" auth-ip-acl="$REMOTE_IP")
REMOTE_MOD=$(ssh "$HOST" pactl load-module module-tunnel-sink server="tcp:$LOCAL_IP:4713" sink_name="$SINK")
AUDIO_ENV=(env "PULSE_SINK=$SINK")
else
echo "pactl missing here or on $HOST - no audio forwarding (sudo apt install pulseaudio-utils on both)"
fi
cleanup() {
[ -n "$REMOTE_MOD" ] && ssh "$HOST" pactl unload-module "$REMOTE_MOD" 2>/dev/null
[ -n "$LOCAL_MOD" ] && pactl unload-module "$LOCAL_MOD" 2>/dev/null
return 0
}
trap cleanup EXIT
case "$MODE" in
# snap Chromium's AppArmor profile only allows wayland-<digit>* sockets;
# waypipe's default random name starts with a letter and gets refused
waypipe) waypipe --display "wayland-$$" ssh "$HOST" "${AUDIO_ENV[@]}" chromium --ozone-platform=wayland ;;
x11) ssh -X "$HOST" "${AUDIO_ENV[@]}" chromium ;;
esac