74 lines
2.7 KiB
Bash
74 lines
2.7 KiB
Bash
#!/usr/bin/env bash
|
|
# Bring the X2 dashboard up ON THE ROBOT and keep it up.
|
|
#
|
|
# The dashboard is served by the robot itself, so the link people open is the
|
|
# robot's own address - http://<robot-ip>:8770. Nothing depends on any laptop
|
|
# being switched on, and when the robot joins a different Wi-Fi the link simply
|
|
# follows its new address.
|
|
#
|
|
# Idempotent by design: it starts only what is not already running, so it is
|
|
# safe to call from cron every minute, from @reboot, and by hand.
|
|
#
|
|
# No `set -u` - the ROS setup scripts read undefined variables.
|
|
|
|
set -e
|
|
|
|
DIR="$(dirname "$(readlink -f "$0")")"
|
|
LOG_DIR="/home/agi/x2_dashboard_logs"
|
|
AGENT_PORT="${X2_AGENT_PORT:-8781}"
|
|
WEB_PORT="${X2_WEB_PORT:-8770}"
|
|
|
|
mkdir -p "$LOG_DIR"
|
|
|
|
listening() {
|
|
ss -ltn 2>/dev/null | grep -q ":$1 "
|
|
}
|
|
|
|
# The previous guard here was `pgrep -f "x2_dashboard/-m backend|backend.server"`,
|
|
# and neither alternative can match the real command line, which is plain
|
|
# `python3 -m backend`. That left the port check as the only guard, and the port
|
|
# is not bound for the first ~10 s of startup - so the every-minute timer fired
|
|
# again mid-boot and launched a second backend on top of the first. That is the
|
|
# recurring "[Errno 98] address already in use" in dashboard.log.
|
|
#
|
|
# Matching on /proc rather than trusting pgrep alone: `pgrep -f` also matches any
|
|
# shell whose command line merely mentions the pattern, so require python argv[0].
|
|
backend_running() {
|
|
local p cmd
|
|
for p in $(pgrep -f 'python3 -m backend' 2>/dev/null); do
|
|
cmd=$(tr '\0' ' ' < "/proc/$p/cmdline" 2>/dev/null)
|
|
case "$cmd" in
|
|
python*|*/python*) return 0 ;;
|
|
esac
|
|
done
|
|
return 1
|
|
}
|
|
|
|
trim() { # keep the logs from growing without bound
|
|
[ -f "$1" ] || return 0
|
|
if [ "$(stat -c%s "$1" 2>/dev/null || echo 0)" -gt 2000000 ]; then
|
|
tail -n 300 "$1" > "$1.tmp" && mv "$1.tmp" "$1"
|
|
fi
|
|
}
|
|
|
|
# 1. the ROS bridge -------------------------------------------------------
|
|
if ! listening "$AGENT_PORT" && ! pgrep -f "x2_agent.py" >/dev/null 2>&1; then
|
|
trim "$LOG_DIR/agent.log"
|
|
echo "[$(date -Is)] starting agent" >> "$LOG_DIR/agent.log"
|
|
setsid nohup "$DIR/run_agent.sh" >> "$LOG_DIR/agent.log" 2>&1 < /dev/null &
|
|
sleep 3
|
|
fi
|
|
|
|
# 2. the web dashboard ----------------------------------------------------
|
|
if ! listening "$WEB_PORT" && ! backend_running; then
|
|
trim "$LOG_DIR/dashboard.log"
|
|
echo "[$(date -Is)] starting dashboard" >> "$LOG_DIR/dashboard.log"
|
|
cd /home/agi/x2_dashboard
|
|
# The dashboard talks to the agent over localhost and needs no ROS itself,
|
|
# but sourcing costs nothing and keeps one environment for both.
|
|
setsid nohup env PYTHONUNBUFFERED=1 python3 -m backend \
|
|
>> "$LOG_DIR/dashboard.log" 2>&1 < /dev/null &
|
|
fi
|
|
|
|
exit 0
|