From 0bace1ce8826a9a1be4003681fab5138f174c275 Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 8 Nov 2026 11:53:04 +0100 Subject: dev: add a no-nginx browser stack script scripts/dev-web.sh builds the server, gateway and app, creates target/dev-web/identity, and runs the game server, webd and a loopback static server. The app accepts a ?ws= override only on loopback so the page and gateway can sit on different local ports; production stays same-origin at /ws. --- scripts/dev-web.sh | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100755 scripts/dev-web.sh (limited to 'scripts/dev-web.sh') diff --git a/scripts/dev-web.sh b/scripts/dev-web.sh new file mode 100755 index 0000000..1faca8a --- /dev/null +++ b/scripts/dev-web.sh @@ -0,0 +1,144 @@ +#!/usr/bin/env bash +# Run the whole browser stack on this machine, without nginx. +# +# ./scripts/dev-web.sh +# ./scripts/dev-web.sh --reset # wipe the local dev database first +# +# It builds the server, the gateway and the browser app, creates a local TLS +# identity under target/dev-web/, and starts: +# +# game server 127.0.0.1:11525 (target/dev-web/server.db) +# webd 127.0.0.1:8890 +# static app 127.0.0.1:8899 (web/play/?ws=ws://127.0.0.1:8890/ws) +# +# The page and the WebSocket are on different loopback ports. The app only +# honours ?ws= on localhost, so this cannot be used to redirect a real player's +# password. In production nginx keeps both on one origin. +# +# Environment overrides: +# ZAGAN_DEV_GAME_PORT=11525 +# ZAGAN_DEV_GATEWAY_PORT=8890 +# ZAGAN_DEV_WEB_PORT=8899 +# ZAGAN_DEV_DIR=target/dev-web +# ZAGAN_DEV_OPEN=1 open the URL in the desktop browser +set -euo pipefail + +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +cd "$ROOT" + +DEV_DIR=${ZAGAN_DEV_DIR:-"$ROOT/target/dev-web"} +mkdir -p "$DEV_DIR" +DEV_DIR=$(cd "$DEV_DIR" && pwd) +GAME_PORT=${ZAGAN_DEV_GAME_PORT:-11525} +GATEWAY_PORT=${ZAGAN_DEV_GATEWAY_PORT:-8890} +WEB_PORT=${ZAGAN_DEV_WEB_PORT:-8899} +ORIGIN="http://127.0.0.1:$WEB_PORT" +URL="$ORIGIN/play/?ws=ws%3A%2F%2F127.0.0.1%3A$GATEWAY_PORT%2Fws" + +die() { echo "dev-web: $*" >&2; exit 1; } + +command -v cargo >/dev/null || die "cargo is required" +command -v openssl >/dev/null || die "openssl is required" +command -v python3 >/dev/null || die "python3 is required for the static server" +command -v ss >/dev/null || die "ss is required to wait for the dev ports" + +if [ "${1:-}" = "--reset" ]; then + rm -f "$DEV_DIR/server.db" + echo "==> removed $DEV_DIR/server.db" +fi + +echo "==> building server, gateway and browser app" +cargo build --quiet --bin server +cargo build --quiet -p zagan-bet-webd --bin zagan-bet-webd +if command -v npm >/dev/null 2>&1; then + if [ ! -d web/play/node_modules ]; then + (cd web/play && npm ci --silent) + fi + (cd web/play && npm run build --silent >/dev/null) +fi + +if [ ! -f "$DEV_DIR/identity.p12" ] || [ ! -f "$DEV_DIR/cert.pem" ]; then + echo "==> creating a local TLS identity" + (cd "$DEV_DIR" && "$ROOT/target/debug/server" --init >/dev/null) +fi + +fingerprint=$(openssl x509 -in "$DEV_DIR/cert.pem" -pubkey -noout \ + | openssl pkey -pubin -outform DER \ + | sha256sum | awk '{print $1}') +[ -n "$fingerprint" ] || die "could not read the local certificate fingerprint" + +for port in "$GAME_PORT" "$GATEWAY_PORT" "$WEB_PORT"; do + if (exec 3<>"/dev/tcp/127.0.0.1/$port") 2>/dev/null; then + exec 3>&- + die "port $port is already in use; stop the other process or set the ZAGAN_DEV_*_PORT override" + fi +done + +pids=() +cleanup() { + trap - EXIT INT TERM + for pid in "${pids[@]}"; do + kill "$pid" 2>/dev/null || true + done + wait 2>/dev/null || true +} +trap cleanup EXIT INT TERM + +echo "==> starting game server on 127.0.0.1:$GAME_PORT" +# The server loads identity.p12 from its working directory. Run it inside the +# dev directory so it never touches the repository's own identity files. +(cd "$DEV_DIR" && exec env SERVER_DB="$DEV_DIR/server.db" \ + "$ROOT/target/debug/server" -i 127.0.0.1 -p "$GAME_PORT") \ + >"$DEV_DIR/server.log" 2>&1 & +pids+=($!) + +echo "==> starting gateway on 127.0.0.1:$GATEWAY_PORT" +ZAGAN_WEB_BIND="127.0.0.1:$GATEWAY_PORT" \ +ZAGAN_WEB_ORIGIN="$ORIGIN" \ +ZAGAN_UPSTREAM="127.0.0.1:$GAME_PORT" \ +ZAGAN_UPSTREAM_FINGERPRINT="$fingerprint" \ +ZAGAN_WEB_COOKIE_SECURE=0 \ +"$ROOT/target/debug/zagan-bet-webd" >"$DEV_DIR/webd.log" 2>&1 & +pids+=($!) + +echo "==> starting static app on 127.0.0.1:$WEB_PORT" +python3 -m http.server "$WEB_PORT" --bind 127.0.0.1 --directory "$ROOT/web" \ + >"$DEV_DIR/static.log" 2>&1 & +pids+=($!) + +wait_port() { + local port=$1 name=$2 + for _ in $(seq 1 100); do + if ss -ltn 2>/dev/null \ + | awk -v p=":$port" '$4 ~ p { found = 1 } END { exit found ? 0 : 1 }'; then + return 0 + fi + sleep 0.1 + done + echo "dev-web: $name did not listen on $port; see $DEV_DIR" >&2 + return 1 +} + +wait_port "$GAME_PORT" "the game server" || exit 1 +wait_port "$GATEWAY_PORT" "the gateway" || exit 1 +wait_port "$WEB_PORT" "the static server" || exit 1 + +cat </dev/null 2>&1 && xdg-open "$URL" >/dev/null 2>&1 || true +fi + +# Stop the script when any child dies unexpectedly as well. +wait -n || true -- cgit v1.2.3