Initial web ui and control for robot
This commit is contained in:
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env bash
|
||||
# Starts the FastAPI backend and Vite frontend for local development.
|
||||
# Run from anywhere — paths are resolved relative to this script.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BACKEND_DIR="$SCRIPT_DIR/backend"
|
||||
FRONTEND_DIR="$SCRIPT_DIR/frontend"
|
||||
VENV="$BACKEND_DIR/.venv"
|
||||
|
||||
# Match whichever ROS_DOMAIN_ID the robot containers are using (default 0).
|
||||
# Override: ROS_DOMAIN_ID=42 ./dev.sh
|
||||
ROS_DOMAIN_ID="${ROS_DOMAIN_ID:-0}"
|
||||
|
||||
# Hostname of the WebRTC signaling server (default: same host as the page).
|
||||
# Override: VITE_WEBRTC_HOST=rapsbot-v2.local ./dev.sh
|
||||
# Or set VITE_WEBRTC_HOST in frontend/.env.local (see .env.local.example).
|
||||
export VITE_WEBRTC_HOST="${VITE_WEBRTC_HOST:-}"
|
||||
|
||||
# ── colour helpers ────────────────────────────────────────────────────────────
|
||||
G='\033[0;32m'; Y='\033[1;33m'; R='\033[0;31m'; NC='\033[0m'
|
||||
info() { echo -e "${G}[webui]${NC} $*"; }
|
||||
warn() { echo -e "${Y}[webui]${NC} $*"; }
|
||||
error() { echo -e "${R}[webui]${NC} $*" >&2; }
|
||||
|
||||
# ── sanity checks ─────────────────────────────────────────────────────────────
|
||||
if [ -z "${ROS_DISTRO:-}" ]; then
|
||||
error "ROS_DISTRO is not set. Source a ROS setup file first, or rebuild the devcontainer."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v node &>/dev/null; then
|
||||
error "Node.js not found. Rebuild the devcontainer to install it (see .devcontainer/Dockerfile)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── backend: venv ─────────────────────────────────────────────────────────────
|
||||
# Prefer the venv baked into the devcontainer image; fall back to a local one.
|
||||
if [ -d "/opt/webui-venv" ]; then
|
||||
VENV="/opt/webui-venv"
|
||||
info "Using devcontainer venv at $VENV"
|
||||
else
|
||||
if [ ! -d "$VENV" ]; then
|
||||
info "Creating Python venv at $VENV..."
|
||||
python3 -m venv "$VENV"
|
||||
fi
|
||||
info "Syncing backend dependencies..."
|
||||
"$VENV/bin/pip" install -q -r "$BACKEND_DIR/requirements.txt"
|
||||
fi
|
||||
|
||||
# ── frontend: npm deps ────────────────────────────────────────────────────────
|
||||
if [ ! -d "$FRONTEND_DIR/node_modules" ]; then
|
||||
info "Installing frontend dependencies..."
|
||||
npm --prefix "$FRONTEND_DIR" install
|
||||
fi
|
||||
|
||||
# ── cleanup on exit ───────────────────────────────────────────────────────────
|
||||
BACKEND_PID=""
|
||||
FRONTEND_PID=""
|
||||
|
||||
cleanup() {
|
||||
warn "Shutting down..."
|
||||
[ -n "$BACKEND_PID" ] && kill "$BACKEND_PID" 2>/dev/null || true
|
||||
[ -n "$FRONTEND_PID" ] && kill "$FRONTEND_PID" 2>/dev/null || true
|
||||
wait "$BACKEND_PID" "$FRONTEND_PID" 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# ── start backend ─────────────────────────────────────────────────────────────
|
||||
info "Starting FastAPI backend on :8080 (ROS_DOMAIN_ID=$ROS_DOMAIN_ID)"
|
||||
(
|
||||
# shellcheck disable=SC1091
|
||||
set +u # ROS setup.bash references AMENT_TRACE_SETUP_FILES without a default
|
||||
source "/opt/ros/$ROS_DISTRO/setup.bash"
|
||||
export ROS_DOMAIN_ID
|
||||
exec "$VENV/bin/python3" "$BACKEND_DIR/main.py"
|
||||
) &
|
||||
BACKEND_PID=$!
|
||||
|
||||
# ── start frontend ────────────────────────────────────────────────────────────
|
||||
info "Starting Vite dev server on :5173"
|
||||
npm --prefix "$FRONTEND_DIR" run dev &
|
||||
FRONTEND_PID=$!
|
||||
|
||||
info "Ready — open http://localhost:5173"
|
||||
info "Press Ctrl+C to stop both processes."
|
||||
echo
|
||||
|
||||
# Exit as soon as either process dies
|
||||
wait -n "$BACKEND_PID" "$FRONTEND_PID"
|
||||
Reference in New Issue
Block a user