Single command to start the interactive map container in the background (auto-restart after reboot), with stop/restart/status/sync/logs/update subcommands. Configuration lives in webapp.env (template provided, git-ignored): remote generation URL, shared token, rsync cache command, periodic sync and allowed network. The SSH key is mounted automatically for rsync, port conflicts are detected before launch, and update pulls the repo, rebuilds the image and restarts. Deploy doc updated: the script is now the recommended install path on the Raspberry Pi, alongside run.sh (foreground) and docker compose.
181 lines
6.4 KiB
Bash
Executable File
181 lines
6.4 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_SYNC_CMD rsync qui remplit le cache local de tuiles
|
|
# LIDAR_AUTO_SYNC_SECONDS resynchronisation périodique (défaut 0 = off)
|
|
# LIDAR_REGEN_CIDR réseau autorisé à lancer les générations
|
|
# (défaut 192.168.1.0/24, vide = restriction levée)
|
|
#
|
|
# 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 sync rsync + régénération des vignettes
|
|
# ./serve-webapp.sh logs suivre les logs du conteneur
|
|
# ./serve-webapp.sh update git pull, rebuild de l'image, redémarrer
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
IMAGE="lidar-webapp"
|
|
CONTAINER="lidar-webapp"
|
|
WEBAPP_PORT="${WEBAPP_PORT:-8973}"
|
|
BASE_URL="http://127.0.0.1:${WEBAPP_PORT}"
|
|
|
|
# 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
|
|
|
|
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 "${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
|
|
if [ -n "${LIDAR_SYNC_CMD:-}" ]; then
|
|
ENV_ARGS+=(-e LIDAR_SYNC_CMD="$LIDAR_SYNC_CMD")
|
|
fi
|
|
if [ -n "${LIDAR_AUTO_SYNC_SECONDS:-}" ]; then
|
|
ENV_ARGS+=(-e LIDAR_AUTO_SYNC_SECONDS="$LIDAR_AUTO_SYNC_SECONDS")
|
|
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
|
|
# Clé SSH du rsync (LIDAR_SYNC_CMD) : 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" \
|
|
"${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 "${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) : http://$(lan_ip):${WEBAPP_PORT}/"
|
|
fi
|
|
echo " Génération distante: ${LIDAR_GENERATION_URL:-non configurée}"
|
|
if [ -n "${LIDAR_SYNC_CMD:-}" ]; then
|
|
if [ -n "${LIDAR_AUTO_SYNC_SECONDS:-}" ] && [ "${LIDAR_AUTO_SYNC_SECONDS}" != "0" ]; then
|
|
echo " Cache local tuiles : rsync (auto toutes les ${LIDAR_AUTO_SYNC_SECONDS}s)"
|
|
else
|
|
echo " Cache local tuiles : rsync (à la demande)"
|
|
fi
|
|
else
|
|
echo " Cache local tuiles : désactivé (LIDAR_SYNC_CMD)"
|
|
fi
|
|
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 "${BASE_URL}/api/sync" 2> /dev/null; then
|
|
echo ""
|
|
else
|
|
echo "Webapp : injoignable sur ${BASE_URL}"
|
|
fi
|
|
}
|
|
|
|
cmd_sync() {
|
|
CODE="$(curl -s -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
|
|
}
|
|
|
|
cmd_update() {
|
|
echo "Mise à jour du code (git pull)..."
|
|
git -C "$SCRIPT_DIR" pull --ff-only
|
|
build_image
|
|
cmd_start
|
|
}
|
|
|
|
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" ;;
|
|
update) cmd_update ;;
|
|
*)
|
|
echo "Usage : $0 [start|stop|restart|status|sync|logs|update]" >&2
|
|
exit 1
|
|
;;
|
|
esac
|