blob: 1faca8a155b58c1d076ee80a5e2b3ee890c47015 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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 <<EOF
Open: $URL
Game server: 127.0.0.1:$GAME_PORT ($DEV_DIR/server.db)
Gateway: 127.0.0.1:$GATEWAY_PORT
Static app: 127.0.0.1:$WEB_PORT
Logs: $DEV_DIR/{server,webd,static}.log
Fingerprint: $fingerprint
Register a new account on first use. Ctrl+C stops all three processes.
EOF
if [ "${ZAGAN_DEV_OPEN:-0}" = "1" ]; then
command -v xdg-open >/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
|