summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-08 11:53:04 +0100
committersalmonik <salmonik@tuta.io>2026-11-08 11:53:04 +0100
commit0bace1ce8826a9a1be4003681fab5138f174c275 (patch)
treebd191ef204486c950e8407718cb2ddb1dad64e44 /scripts
parentweb: link the GPL source from the play page; normalise gateway config (diff)
downloadzagan-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-xscripts/dev-web.sh144
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
24set -euo pipefail
25
26ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
27cd "$ROOT"
28
29DEV_DIR=${ZAGAN_DEV_DIR:-"$ROOT/target/dev-web"}
30mkdir -p "$DEV_DIR"
31DEV_DIR=$(cd "$DEV_DIR" && pwd)
32GAME_PORT=${ZAGAN_DEV_GAME_PORT:-11525}
33GATEWAY_PORT=${ZAGAN_DEV_GATEWAY_PORT:-8890}
34WEB_PORT=${ZAGAN_DEV_WEB_PORT:-8899}
35ORIGIN="http://127.0.0.1:$WEB_PORT"
36URL="$ORIGIN/play/?ws=ws%3A%2F%2F127.0.0.1%3A$GATEWAY_PORT%2Fws"
37
38die() { echo "dev-web: $*" >&2; exit 1; }
39
40command -v cargo >/dev/null || die "cargo is required"
41command -v openssl >/dev/null || die "openssl is required"
42command -v python3 >/dev/null || die "python3 is required for the static server"
43command -v ss >/dev/null || die "ss is required to wait for the dev ports"
44
45if [ "${1:-}" = "--reset" ]; then
46 rm -f "$DEV_DIR/server.db"
47 echo "==> removed $DEV_DIR/server.db"
48fi
49
50echo "==> building server, gateway and browser app"
51cargo build --quiet --bin server
52cargo build --quiet -p zagan-bet-webd --bin zagan-bet-webd
53if 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)
58fi
59
60if [ ! -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)
63fi
64
65fingerprint=$(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
70for 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
75done
76
77pids=()
78cleanup() {
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}
85trap cleanup EXIT INT TERM
86
87echo "==> 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 &
93pids+=($!)
94
95echo "==> starting gateway on 127.0.0.1:$GATEWAY_PORT"
96ZAGAN_WEB_BIND="127.0.0.1:$GATEWAY_PORT" \
97ZAGAN_WEB_ORIGIN="$ORIGIN" \
98ZAGAN_UPSTREAM="127.0.0.1:$GAME_PORT" \
99ZAGAN_UPSTREAM_FINGERPRINT="$fingerprint" \
100ZAGAN_WEB_COOKIE_SECURE=0 \
101"$ROOT/target/debug/zagan-bet-webd" >"$DEV_DIR/webd.log" 2>&1 &
102pids+=($!)
103
104echo "==> starting static app on 127.0.0.1:$WEB_PORT"
105python3 -m http.server "$WEB_PORT" --bind 127.0.0.1 --directory "$ROOT/web" \
106 >"$DEV_DIR/static.log" 2>&1 &
107pids+=($!)
108
109wait_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
122wait_port "$GAME_PORT" "the game server" || exit 1
123wait_port "$GATEWAY_PORT" "the gateway" || exit 1
124wait_port "$WEB_PORT" "the static server" || exit 1
125
126cat <<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.
137EOF
138
139if [ "${ZAGAN_DEV_OPEN:-0}" = "1" ]; then
140 command -v xdg-open >/dev/null 2>&1 && xdg-open "$URL" >/dev/null 2>&1 || true
141fi
142
143# Stop the script when any child dies unexpectedly as well.
144wait -n || true