Files
lidar_rendu/serve-webapp.sh
Antoine Jacquin f024514427 Sélection de tuiles au clic, file d'attente et rafraîchissement fiable
- Clic sur la carte pour choisir des dalles précises, même sans données
  existantes (via /api/cell) ; les zones dessinées s'ajoutent à la
  sélection au lieu de la remplacer
- Une demande lancée pendant un run part en file d'attente côté serveur
  et démarre à la fin du travail en cours (plus de refus 409), file
  vidable depuis l'interface
- Tuiles et interface toujours fraîches : images servies sans cache
  navigateur (revalidation 304), rechargement de la carte seulement une
  fois le rebuild de l'index terminé
- serve-webapp.sh : sous-commande update retirée, documentation de
  déploiement corrigée en conséquence
2026-09-16 22:37:53 +02:00

188 lines
7.0 KiB
Bash
Executable File

#!/bin/bash
# Stack webapp LiDAR — gestion du conteneur carte interactive sur la machine
# légère (Raspberry Pi). Cf. docs/DEPLOY_WEBAPP.md.
#
# Configuration : variables dans webapp.env (modèle : webapp.env.example,
# non versionné) ou exportées dans l'environnement :
# WEBAPP_PORT port hôte (défaut 8973)
# LIDAR_GENERATION_URL machine de traitement (ex. http://192.168.1.50:8973)
# LIDAR_REMOTE_TOKEN jeton si la machine exige LIDAR_API_TOKEN
# LIDAR_REGEN_CIDR réseau autorisé à lancer les générations
# (défaut 192.168.1.0/24, vide = restriction levée)
#
# GPS sur téléphone (optionnel) : l'API Geolocation exige une connexion
# sécurisée. ./make-tls-cert.sh crée un certificat auto-signé dans ./tls ;
# dès qu'il est présent, ce script sert la carte en HTTPS (https://<hôte>:port)
# et le bouton ⌖ « centrer sur la position GPS » fonctionne sur téléphone
# (accepter l'avertissement « certificat non fiable » une fois).
#
# Usage :
# ./serve-webapp.sh [start] démarrer (arrière-plan, redémarrage auto)
# ./serve-webapp.sh stop arrêter et supprimer le conteneur
# ./serve-webapp.sh restart redémarrer (relit webapp.env)
# ./serve-webapp.sh status état du conteneur et de la dernière sync
# ./serve-webapp.sh sync forcer un rebuild + régénération des vignettes
# ./serve-webapp.sh logs suivre les logs du conteneur
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
IMAGE="lidar-webapp"
CONTAINER="lidar-webapp"
# Configuration locale (non versionnée) : webapp.env surcharge l'environnement
if [ -f "${SCRIPT_DIR}/webapp.env" ]; then
set -a
# shellcheck disable=SC1091
. "${SCRIPT_DIR}/webapp.env"
set +a
fi
WEBAPP_PORT="${WEBAPP_PORT:-8973}"
# HTTPS (requis pour la géolocalisation GPS depuis un téléphone) : l'API
# Geolocation n'existe qu'en contexte sécurisé. Si le certificat auto-signé
# ./tls (cf. ./make-tls-cert.sh) est présent, la carte est servie en
# https://<hôte>:PORT ; le téléphone accepte l'avertissement « certificat non
# fiable » une fois. Sans certificat : HTTP (le bouton GPS est indisponible).
TLS_DIR="${SCRIPT_DIR}/tls"
if [ -f "${TLS_DIR}/webapp.crt" ] && [ -f "${TLS_DIR}/webapp.key" ]; then
SCHEME=https
KFLAG=" -k" # -k : les sondes locales tolèrent le certificat auto-signé
else
SCHEME=http
KFLAG=""
fi
BASE_URL="${SCHEME}://127.0.0.1:${WEBAPP_PORT}"
CMD="${1:-start}"
build_image() {
echo "Build de l'image webapp (cache Docker)..."
if ! docker build -f "${SCRIPT_DIR}/Dockerfile.webapp" -t "$IMAGE" "$SCRIPT_DIR" > /tmp/lidar_webapp_build.log 2>&1; then
cat /tmp/lidar_webapp_build.log >&2
echo "Échec du build (journal : /tmp/lidar_webapp_build.log)" >&2
exit 1
fi
}
lan_ip() {
hostname -I 2> /dev/null | awk '{print $1}'
}
cmd_start() {
mkdir -p "${SCRIPT_DIR}/output"
if curl -fsS${KFLAG} "${BASE_URL}/api/status" > /dev/null 2>&1; then
echo "Le port ${WEBAPP_PORT} répond déjà (webapp déjà lancée ?)." >&2
echo "Arrêter l'existant, ou relancer avec un autre port : WEBAPP_PORT=9000 $0" >&2
exit 1
fi
if ! docker image inspect "$IMAGE" > /dev/null 2>&1; then
build_image
fi
ENV_ARGS=()
if [ -n "${LIDAR_GENERATION_URL:-}" ]; then
ENV_ARGS+=(-e LIDAR_GENERATION_URL="$LIDAR_GENERATION_URL")
fi
if [ -n "${LIDAR_REMOTE_TOKEN:-}" ]; then
ENV_ARGS+=(-e LIDAR_REMOTE_TOKEN="$LIDAR_REMOTE_TOKEN")
fi
# Définie même vide (= restriction levée) ; absente = défaut webapp.py
if [ -n "${LIDAR_REGEN_CIDR+x}" ]; then
ENV_ARGS+=(-e LIDAR_REGEN_CIDR="${LIDAR_REGEN_CIDR:-}")
fi
# Certificat auto-signé (HTTPS → GPS téléphone) : monté en lecture seule
# et activé via LIDAR_SSL_CERTFILE / LIDAR_SSL_KEYFILE (cf. make-tls-cert.sh).
TLS_ARGS=()
if [ "$SCHEME" = "https" ]; then
TLS_ARGS+=(-v "${TLS_DIR}:/app/tls:ro")
TLS_ARGS+=(-e LIDAR_SSL_CERTFILE=/app/tls/webapp.crt)
TLS_ARGS+=(-e LIDAR_SSL_KEYFILE=/app/tls/webapp.key)
fi
# Clé SSH du hôte (déploiement, git pull distant) : montée en lecture seule si présente
SSH_ARGS=()
if [ -d "${HOME}/.ssh" ]; then
SSH_ARGS+=(-v "${HOME}/.ssh:/home/lidar/.ssh:ro")
fi
docker rm -f "$CONTAINER" > /dev/null 2>&1 || true
docker run -d --init \
--name "$CONTAINER" \
--restart unless-stopped \
--user 1000:1000 \
-p "${WEBAPP_PORT}:8973" \
-v "${SCRIPT_DIR}/output:/data/output" \
"${TLS_ARGS[@]}" \
"${SSH_ARGS[@]}" \
-e LIDAR_OUTPUT_DIR=/data/output \
"${ENV_ARGS[@]}" \
"$IMAGE" > /dev/null
echo -n "Attente du serveur sur le port ${WEBAPP_PORT}..."
UP=0
for _ in $(seq 1 30); do
if curl -fsS${KFLAG} "${BASE_URL}/api/status" > /dev/null 2>&1; then
UP=1
break
fi
sleep 1
done
if [ "$UP" != "1" ]; then
echo " KO (voir ./serve-webapp.sh logs)" >&2
exit 1
fi
echo " OK"
echo "============================================"
echo " Carte LiDAR — webapp (${CONTAINER})"
echo "============================================"
echo " URL : ${BASE_URL}/"
if [ -n "$(lan_ip)" ]; then
echo " URL (LAN) : ${SCHEME}://$(lan_ip):${WEBAPP_PORT}/"
fi
if [ "$SCHEME" = "https" ]; then
echo " HTTPS (GPS tél.) : actif — sur le téléphone, acceptez l'avertissement « certificat non fiable »"
fi
echo " Génération distante: ${LIDAR_GENERATION_URL:-non configurée}"
echo " Cache local tuiles : à la demande (LIDAR_GENERATION_URL)"
echo "============================================"
}
cmd_stop() {
docker rm -f "$CONTAINER" > /dev/null 2>&1 || true
echo "Conteneur ${CONTAINER} arrêté."
}
cmd_status() {
if docker ps --format '{{.Names}}' 2> /dev/null | grep -qx "$CONTAINER"; then
echo "Conteneur : ${CONTAINER} en cours d'exécution ($(docker ps --filter name="^${CONTAINER}$" --format '{{.Status}}'))"
else
echo "Conteneur : ${CONTAINER} arrêté"
fi
if curl -fsS${KFLAG} "${BASE_URL}/api/sync" 2> /dev/null; then
echo ""
else
echo "Webapp : injoignable sur ${BASE_URL}"
fi
}
cmd_sync() {
CODE="$(curl -s${KFLAG} -o /dev/null -w '%{http_code}' -X POST "${BASE_URL}/api/sync" || true)"
case "$CODE" in
200) echo "Sync lancée (suivi : ./serve-webapp.sh status, logs : ./serve-webapp.sh logs)" ;;
409) echo "Une sync est déjà en cours (suivi : ./serve-webapp.sh status)" ;;
*)
echo "Échec : HTTP ${CODE:-pas de réponse} (webapp injoignable sur ${BASE_URL} ?)" >&2
exit 1
;;
esac
}
case "$CMD" in
start) cmd_start ;;
stop) cmd_stop ;;
restart) cmd_stop; cmd_start ;;
status) cmd_status ;;
sync) cmd_sync ;;
logs) exec docker logs -f "$CONTAINER" ;;
*)
echo "Usage : $0 [start|stop|restart|status|sync|logs]" >&2
exit 1
;;
esac