diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-08 11:53:04 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-08 11:53:04 +0100 |
| commit | 0bace1ce8826a9a1be4003681fab5138f174c275 (patch) | |
| tree | bd191ef204486c950e8407718cb2ddb1dad64e44 /scripts | |
| parent | web: link the GPL source from the play page; normalise gateway config (diff) | |
| download | zagan-bet-0bace1ce8826a9a1be4003681fab5138f174c275.tar.gz zagan-bet-0bace1ce8826a9a1be4003681fab5138f174c275.zip | |
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.
Diffstat (limited to '')
| -rwxr-xr-x | scripts/dev-web.sh | 144 |
1 files changed, 144 insertions, 0 deletions
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 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | # Run the whole browser stack on this machine, without nginx. | ||
| 3 | # | ||
| 4 | # ./scripts/dev-web.sh | ||
| 5 | # ./scripts/dev-web.sh --reset # wipe the local dev database first | ||
| 6 | # | ||
| 7 | # It builds the server, the gateway and the browser app, creates a local TLS | ||
| 8 | # identity under target/dev-web/, and starts: | ||
| 9 | # | ||
| 10 | # game server 127.0.0.1:11525 (target/dev-web/server.db) | ||
| 11 | # webd 127.0.0.1:8890 | ||
| 12 | # static app 127.0.0.1:8899 (web/play/?ws=ws://127.0.0.1:8890/ws) | ||
| 13 | # | ||
| 14 | # The page and the WebSocket are on different loopback ports. The app only | ||
| 15 | # honours ?ws= on localhost, so this cannot be used to redirect a real player's | ||
| 16 | # password. In production nginx keeps both on one origin. | ||
| 17 | # | ||
| 18 | # Environment overrides: | ||
| 19 | # ZAGAN_DEV_GAME_PORT=11525 | ||
| 20 | # ZAGAN_DEV_GATEWAY_PORT=8890 | ||
| 21 | # ZAGAN_DEV_WEB_PORT=8899 | ||
| 22 | # ZAGAN_DEV_DIR=target/dev-web | ||
| 23 | # ZAGAN_DEV_OPEN=1 open the URL in the desktop browser | ||
| 24 | set -euo pipefail | ||
| 25 | |||
| 26 | ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) | ||
| 27 | cd "$ROOT" | ||
| 28 | |||
| 29 | DEV_DIR=${ZAGAN_DEV_DIR:-"$ROOT/target/dev-web"} | ||
| 30 | mkdir -p "$DEV_DIR" | ||
| 31 | DEV_DIR=$(cd "$DEV_DIR" && pwd) | ||
| 32 | GAME_PORT=${ZAGAN_DEV_GAME_PORT:-11525} | ||
| 33 | GATEWAY_PORT=${ZAGAN_DEV_GATEWAY_PORT:-8890} | ||
| 34 | WEB_PORT=${ZAGAN_DEV_WEB_PORT:-8899} | ||
| 35 | ORIGIN="http://127.0.0.1:$WEB_PORT" | ||
| 36 | URL="$ORIGIN/play/?ws=ws%3A%2F%2F127.0.0.1%3A$GATEWAY_PORT%2Fws" | ||
| 37 | |||
| 38 | die() { echo "dev-web: $*" >&2; exit 1; } | ||
| 39 | |||
| 40 | command -v cargo >/dev/null || die "cargo is required" | ||
| 41 | command -v openssl >/dev/null || die "openssl is required" | ||
| 42 | command -v python3 >/dev/null || die "python3 is required for the static server" | ||
| 43 | command -v ss >/dev/null || die "ss is required to wait for the dev ports" | ||
| 44 | |||
| 45 | if [ "${1:-}" = "--reset" ]; then | ||
| 46 | rm -f "$DEV_DIR/server.db" | ||
| 47 | echo "==> removed $DEV_DIR/server.db" | ||
| 48 | fi | ||
| 49 | |||
| 50 | echo "==> building server, gateway and browser app" | ||
| 51 | cargo build --quiet --bin server | ||
| 52 | cargo build --quiet -p zagan-bet-webd --bin zagan-bet-webd | ||
| 53 | if command -v npm >/dev/null 2>&1; then | ||
| 54 | if [ ! -d web/play/node_modules ]; then | ||
| 55 | (cd web/play && npm ci --silent) | ||
| 56 | fi | ||
| 57 | (cd web/play && npm run build --silent >/dev/null) | ||
| 58 | fi | ||
| 59 | |||
| 60 | if [ ! -f "$DEV_DIR/identity.p12" ] || [ ! -f "$DEV_DIR/cert.pem" ]; then | ||
| 61 | echo "==> creating a local TLS identity" | ||
| 62 | (cd "$DEV_DIR" && "$ROOT/target/debug/server" --init >/dev/null) | ||
| 63 | fi | ||
| 64 | |||
| 65 | fingerprint=$(openssl x509 -in "$DEV_DIR/cert.pem" -pubkey -noout \ | ||
| 66 | | openssl pkey -pubin -outform DER \ | ||
| 67 | | sha256sum | awk '{print $1}') | ||
| 68 | [ -n "$fingerprint" ] || die "could not read the local certificate fingerprint" | ||
| 69 | |||
| 70 | for port in "$GAME_PORT" "$GATEWAY_PORT" "$WEB_PORT"; do | ||
| 71 | if (exec 3<>"/dev/tcp/127.0.0.1/$port") 2>/dev/null; then | ||
| 72 | exec 3>&- | ||
| 73 | die "port $port is already in use; stop the other process or set the ZAGAN_DEV_*_PORT override" | ||
| 74 | fi | ||
| 75 | done | ||
| 76 | |||
| 77 | pids=() | ||
| 78 | cleanup() { | ||
| 79 | trap - EXIT INT TERM | ||
| 80 | for pid in "${pids[@]}"; do | ||
| 81 | kill "$pid" 2>/dev/null || true | ||
| 82 | done | ||
| 83 | wait 2>/dev/null || true | ||
| 84 | } | ||
| 85 | trap cleanup EXIT INT TERM | ||
| 86 | |||
| 87 | echo "==> starting game server on 127.0.0.1:$GAME_PORT" | ||
| 88 | # The server loads identity.p12 from its working directory. Run it inside the | ||
| 89 | # dev directory so it never touches the repository's own identity files. | ||
| 90 | (cd "$DEV_DIR" && exec env SERVER_DB="$DEV_DIR/server.db" \ | ||
| 91 | "$ROOT/target/debug/server" -i 127.0.0.1 -p "$GAME_PORT") \ | ||
| 92 | >"$DEV_DIR/server.log" 2>&1 & | ||
| 93 | pids+=($!) | ||
| 94 | |||
| 95 | echo "==> starting gateway on 127.0.0.1:$GATEWAY_PORT" | ||
| 96 | ZAGAN_WEB_BIND="127.0.0.1:$GATEWAY_PORT" \ | ||
| 97 | ZAGAN_WEB_ORIGIN="$ORIGIN" \ | ||
| 98 | ZAGAN_UPSTREAM="127.0.0.1:$GAME_PORT" \ | ||
| 99 | ZAGAN_UPSTREAM_FINGERPRINT="$fingerprint" \ | ||
| 100 | ZAGAN_WEB_COOKIE_SECURE=0 \ | ||
| 101 | "$ROOT/target/debug/zagan-bet-webd" >"$DEV_DIR/webd.log" 2>&1 & | ||
| 102 | pids+=($!) | ||
| 103 | |||
| 104 | echo "==> starting static app on 127.0.0.1:$WEB_PORT" | ||
| 105 | python3 -m http.server "$WEB_PORT" --bind 127.0.0.1 --directory "$ROOT/web" \ | ||
| 106 | >"$DEV_DIR/static.log" 2>&1 & | ||
| 107 | pids+=($!) | ||
| 108 | |||
| 109 | wait_port() { | ||
| 110 | local port=$1 name=$2 | ||
| 111 | for _ in $(seq 1 100); do | ||
| 112 | if ss -ltn 2>/dev/null \ | ||
| 113 | | awk -v p=":$port" '$4 ~ p { found = 1 } END { exit found ? 0 : 1 }'; then | ||
| 114 | return 0 | ||
| 115 | fi | ||
| 116 | sleep 0.1 | ||
| 117 | done | ||
| 118 | echo "dev-web: $name did not listen on $port; see $DEV_DIR" >&2 | ||
| 119 | return 1 | ||
| 120 | } | ||
| 121 | |||
| 122 | wait_port "$GAME_PORT" "the game server" || exit 1 | ||
| 123 | wait_port "$GATEWAY_PORT" "the gateway" || exit 1 | ||
| 124 | wait_port "$WEB_PORT" "the static server" || exit 1 | ||
| 125 | |||
| 126 | cat <<EOF | ||
| 127 | |||
| 128 | Open: $URL | ||
| 129 | |||
| 130 | Game server: 127.0.0.1:$GAME_PORT ($DEV_DIR/server.db) | ||
| 131 | Gateway: 127.0.0.1:$GATEWAY_PORT | ||
| 132 | Static app: 127.0.0.1:$WEB_PORT | ||
| 133 | Logs: $DEV_DIR/{server,webd,static}.log | ||
| 134 | Fingerprint: $fingerprint | ||
| 135 | |||
| 136 | Register a new account on first use. Ctrl+C stops all three processes. | ||
| 137 | EOF | ||
| 138 | |||
| 139 | if [ "${ZAGAN_DEV_OPEN:-0}" = "1" ]; then | ||
| 140 | command -v xdg-open >/dev/null 2>&1 && xdg-open "$URL" >/dev/null 2>&1 || true | ||
| 141 | fi | ||
| 142 | |||
| 143 | # Stop the script when any child dies unexpectedly as well. | ||
| 144 | wait -n || true | ||
