Test server

This commit is contained in:
Anatoly Antonov 2026-07-04 04:18:36 +09:00
parent 43c120df4c
commit 1e2a276126
3 changed files with 317 additions and 6 deletions

159
scripts/demo-stack.sh Executable file
View file

@ -0,0 +1,159 @@
#!/usr/bin/env bash
# Boot the side-by-side demo: one synthetic ground station feeding BOTH UIs
# through the real Django backend (production topology).
#
# test_server.py --push ──▶ Django :8000 ──▶ leaflet_svelte :5173 (/track)
# └──▶ telemetry-dashboard :5174
#
# The station flies along mock_prediction.json (the real predict) with a
# bounded random drift, if that file exists at the repo root.
#
# Adapted from leaflet_svelte/scripts/run-stack.sh (paths updated after the
# repo move; DJANGO_ENV is NOT set so Django uses the local sqlite db).
#
# Usage:
# scripts/demo-stack.sh # start everything
# scripts/demo-stack.sh restart-flight # начать полёт заново (станция + чистка истории)
# scripts/demo-stack.sh stop # stop everything
set -euo pipefail
ROOT=/home/anton/stratoflights
BACKEND_DIR=$ROOT/stratoflights
LEAFLET_DIR=$ROOT/leaflet_svelte
DASH_DIR=$ROOT/telemetry-dashboard
TRAJECTORY=$ROOT/mock_prediction.json
PID_DIR=/tmp/strato-demo
SPEEDUP=${SPEEDUP:-20}
provision() { # prints "SAT TOKEN"
(cd "$BACKEND_DIR" && python3 - <<'EOF'
import os, django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'stratoflights.settings')
django.setup()
from stratoflights_api.models import Satellite, User
from rest_framework.authtoken.models import Token
u = User.objects.get(username='demo')
sat, _ = Satellite.objects.get_or_create(name='demo-balloon', user=u)
u.satellites.add(sat)
token, _ = Token.objects.get_or_create(user=u)
print(sat.id, token.key)
EOF
)
}
wipe_history() {
(cd "$BACKEND_DIR" && python3 - <<'EOF'
import os, django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'stratoflights.settings')
django.setup()
from stratoflights_api.models import TelemetryPacket
n, _ = TelemetryPacket.objects.filter(satellite__name='demo-balloon').delete()
print(f"история очищена: {n} пакетов")
EOF
)
}
kill_station() {
pkill -f 'test_server.py --push' 2>/dev/null && sleep 1 || true
rm -f "$PID_DIR/station.pid"
}
start_station() { # $1=SAT $2=TOKEN
local traj_args=()
[[ -f "$TRAJECTORY" ]] && traj_args=(--trajectory "$TRAJECTORY")
echo "starting synthetic ground station (speedup x$SPEEDUP)"
cd "$DASH_DIR"
python3 -u test_server.py --push ws://localhost:8000 \
--satellite "$1" --token "$2" \
--interval 1 --speedup "$SPEEDUP" "${traj_args[@]}" \
> /tmp/strato-demo-station.log 2>&1 &
echo $! > "$PID_DIR/station.pid"
}
case "${1:-}" in
stop)
for f in "$PID_DIR"/*.pid; do
[[ -f "$f" ]] && kill "$(cat "$f")" 2>/dev/null && echo "stopped $(basename "$f" .pid)"
rm -f "$f"
done
exit 0
;;
restart-flight)
mkdir -p "$PID_DIR"
kill_station
wipe_history
read -r SAT TOKEN < <(provision)
start_station "$SAT" "$TOKEN"
echo "полёт перезапущен с нуля. Нажми Отключиться/Подключиться в обоих окнах,"
echo "чтобы сбросить старые графики (история в БД уже чистая)."
exit 0
;;
esac
mkdir -p "$PID_DIR"
# --- fake predictor on :8080 (TawhiriClient's hardcoded port) ------------------
# Serves the mock_prediction trajectory, so «Запустить прогноз» in leaflet
# returns exactly the flight the demo station is flying.
if ! ss -tlnp 2>/dev/null | grep -q ':8080'; then
echo "starting fake predictor on :8080"
FAKE_TAWHIRI_TRAJECTORY="$TRAJECTORY" \
python3 -u "$LEAFLET_DIR/tests/e2e/fake_tawhiri.py" 8080 \
> /tmp/strato-demo-predictor.log 2>&1 &
echo $! > "$PID_DIR/predictor.pid"
fi
# --- Django (sqlite dev settings) --------------------------------------------
# Restart if it's ours (pid file) so env changes (CSRF origins) apply.
if [[ -f "$PID_DIR/django.pid" ]] && kill -0 "$(cat "$PID_DIR/django.pid")" 2>/dev/null; then
kill "$(cat "$PID_DIR/django.pid")" 2>/dev/null || true
sleep 1
fi
if ! ss -tlnp 2>/dev/null | grep -q ':8000'; then
echo "starting Django on :8000"
cd "$BACKEND_DIR"
DEBUG=True \
ALLOWED_HOSTS=localhost,127.0.0.1 \
CSRF_TRUSTED_ORIGINS="http://localhost:5173,http://localhost:5174,http://localhost:8000,http://127.0.0.1:5173,http://127.0.0.1:5174,http://127.0.0.1:8000" \
python3 manage.py runserver 0.0.0.0:8000 > /tmp/strato-demo-django.log 2>&1 &
echo $! > "$PID_DIR/django.pid"
sleep 3
else
echo "ВНИМАНИЕ: :8000 занят не нашим Django — если ловишь CSRF-ошибку, останови его и перезапусти этот скрипт"
fi
read -r SAT TOKEN < <(provision)
# --- synthetic ground station (push mode) -------------------------------------
# всегда стартуем полёт с нуля: старую станцию гасим, историю чистим
kill_station
wipe_history
start_station "$SAT" "$TOKEN"
# --- leaflet_svelte -----------------------------------------------------------
if ! ss -tlnp 2>/dev/null | grep -q ':5173'; then
echo "starting leaflet_svelte on :5173"
cd "$LEAFLET_DIR"
VITE_USE_MOCK_API=false VITE_API_BASE_URL=/api VITE_API_PROXY_TARGET=http://localhost:8000 \
npm run dev -- --port 5173 --strictPort > /tmp/strato-demo-leaflet.log 2>&1 &
echo $! > "$PID_DIR/leaflet.pid"
fi
# --- telemetry-dashboard ------------------------------------------------------
if ! ss -tlnp 2>/dev/null | grep -q ':5174'; then
echo "starting telemetry-dashboard on :5174"
cd "$DASH_DIR"
VITE_DEFAULT_WS_URL="ws://localhost:8000/api/ws/satellite/$SAT/telemetry/" \
npm run dev -- --port 5174 --strictPort > /tmp/strato-demo-dash.log 2>&1 &
echo $! > "$PID_DIR/dash.pid"
fi
sleep 2
echo
echo "--- demo stack ready ---"
echo " satellite UUID: $SAT"
echo " leaflet (карта): http://localhost:5173/track (login: demo/demo, ID спутника выше)"
echo " дэшборд (приборы): http://localhost:5174/ (ws://localhost:8000/api/ws/satellite/$SAT/telemetry/)"
echo
echo "перезапуск полёта: scripts/demo-stack.sh restart-flight"
echo "logs: /tmp/strato-demo-*.log stop: scripts/demo-stack.sh stop"