#!/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"